Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit 32f3774

Browse files
authored
Merge pull request #630 from grafana/bug/race-pendingdoc
Add mutex to prevent data race on pendingDoc and use mutex when reading frame.inflightRequests
2 parents bab50db + 168be19 commit 32f3774

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

common/frame.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ type Frame struct {
7070
inflightRequestsMu sync.RWMutex
7171
inflightRequests map[network.RequestID]bool
7272

73-
currentDocument *DocumentInfo
74-
pendingDocument *DocumentInfo
73+
currentDocument *DocumentInfo
74+
pendingDocumentMu sync.RWMutex
75+
pendingDocument *DocumentInfo
7576

7677
log *log.Logger
7778
}
@@ -147,6 +148,18 @@ func (f *Frame) inflightRequestsLen() int {
147148
return len(f.inflightRequests)
148149
}
149150

151+
func (f *Frame) cloneInflightRequests() map[network.RequestID]bool {
152+
f.inflightRequestsMu.RLock()
153+
defer f.inflightRequestsMu.RUnlock()
154+
155+
ifr := make(map[network.RequestID]bool)
156+
for k, v := range f.inflightRequests {
157+
ifr[k] = v
158+
}
159+
160+
return ifr
161+
}
162+
150163
func (f *Frame) clearLifecycle() {
151164
f.log.Debugf("Frame:clearLifecycle", "fid:%s furl:%q", f.ID(), f.URL())
152165

common/frame_manager.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,18 @@ func (m *FrameManager) frameAbortedNavigation(frameID cdp.FrameID, errorText, do
117117
defer m.framesMu.Unlock()
118118

119119
frame := m.frames[frameID]
120-
if frame == nil || frame.pendingDocument == nil {
120+
if frame == nil {
121+
return
122+
}
123+
124+
frame.pendingDocumentMu.Lock()
125+
126+
if frame.pendingDocument == nil {
127+
frame.pendingDocumentMu.Unlock()
121128
return
122129
}
123130
if documentID != "" && frame.pendingDocument.documentID != documentID {
131+
frame.pendingDocumentMu.Unlock()
124132
return
125133
}
126134

@@ -135,6 +143,9 @@ func (m *FrameManager) frameAbortedNavigation(frameID cdp.FrameID, errorText, do
135143
err: errors.New(errorText),
136144
}
137145
frame.pendingDocument = nil
146+
147+
frame.pendingDocumentMu.Unlock()
148+
138149
frame.emit(EventFrameNavigation, ne)
139150
}
140151

@@ -266,6 +277,9 @@ func (m *FrameManager) frameNavigated(frameID cdp.FrameID, parentFrameID cdp.Fra
266277

267278
frame.navigated(name, url, documentID)
268279

280+
frame.pendingDocumentMu.Lock()
281+
defer frame.pendingDocumentMu.Unlock()
282+
269283
var (
270284
keepPending *DocumentInfo
271285
pendingDocument = frame.pendingDocument
@@ -362,6 +376,9 @@ func (m *FrameManager) frameRequestedNavigation(frameID cdp.FrameID, url string,
362376
b.AddFrameNavigation(frame)
363377
}
364378

379+
frame.pendingDocumentMu.Lock()
380+
defer frame.pendingDocumentMu.Unlock()
381+
365382
if frame.pendingDocument != nil && frame.pendingDocument.documentID == documentID {
366383
m.logger.Debugf("FrameManager:frameRequestedNavigation:return",
367384
"fmid:%d fid:%v furl:%s url:%s docid:%s pdocid:%s pdoc:dontSet",
@@ -433,29 +450,43 @@ func (m *FrameManager) requestFailed(req *Request, canceled bool) {
433450
}
434451
frame.deleteRequest(req.getID())
435452

436-
switch rc := frame.inflightRequestsLen(); {
453+
ifr := frame.cloneInflightRequests()
454+
switch rc := len(ifr); {
437455
case rc == 0:
438456
frame.startNetworkIdleTimer()
439457
case rc <= 10:
440-
for reqID := range frame.inflightRequests {
458+
for reqID := range ifr {
441459
req := frame.requestByID(reqID)
442460

461+
if req == nil {
462+
m.logger.Debugf("FrameManager:requestFailed:rc<=10 request is nil",
463+
"reqID:%s frameID:%s",
464+
reqID, frame.ID())
465+
continue
466+
}
467+
443468
m.logger.Debugf("FrameManager:requestFailed:rc<=10",
444469
"reqID:%s inflightURL:%s frameID:%s",
445470
reqID, req.URL(), frame.ID())
446471
}
447472
}
448473

474+
frame.pendingDocumentMu.RLock()
449475
if frame.pendingDocument == nil || frame.pendingDocument.request != req {
450476
m.logger.Debugf("FrameManager:requestFailed:return", "fmid:%d pdoc:nil", m.ID())
477+
frame.pendingDocumentMu.RUnlock()
451478
return
452479
}
480+
453481
errorText := req.errorText
454482
if canceled {
455483
errorText += "; maybe frame was detached?"
456484
}
457-
m.frameAbortedNavigation(cdp.FrameID(frame.ID()), errorText,
458-
frame.pendingDocument.documentID)
485+
486+
docID := frame.pendingDocument.documentID
487+
frame.pendingDocumentMu.RUnlock()
488+
489+
m.frameAbortedNavigation(cdp.FrameID(frame.ID()), errorText, docID)
459490
}
460491

461492
func (m *FrameManager) requestFinished(req *Request) {
@@ -510,7 +541,9 @@ func (m *FrameManager) requestStarted(req *Request) {
510541
frame.stopNetworkIdleTimer()
511542
}
512543
if req.documentID != "" {
544+
frame.pendingDocumentMu.Lock()
513545
frame.pendingDocument = &DocumentInfo{documentID: req.documentID, request: req}
546+
frame.pendingDocumentMu.Unlock()
514547
}
515548
m.logger.Debugf("FrameManager:requestStarted", "fmid:%d rurl:%s pdoc:nil", m.ID(), req.URL())
516549
}

0 commit comments

Comments
 (0)