Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,31 @@ func (f *Frame) setContext(world executionWorld, execCtx frameExecutionContext)
panic(err)
}

// There is a race condition when it comes to attaching iframes and the
// execution context that apply to these frames. What usually occurs is:
//
// 1. An exec context for about:blank is first set;
// 2. A new set event is received for exec context for the url pointing
// to the actual destination for the iframe;
// 3. Finally the execution context for about:blank is destroyed, not
// for the second execution context.
//
// This is the order of events when iframes are in use on a site, and
// so it is safe to nil the original execution context and overwrite it
// with the second one.
//
// The exec context destroyed event will not remove the new exec context
// since the ids do not match.
//
// If we didn't overwrite the first execCtx with the new one, then
// waitForExecutionContext could end up waiting indefinitely since all
// execCtx were destroyed.
if f.executionContexts[world] != nil {
f.log.Debugf("Frame:setContext", "fid:%s furl:%q ectxid:%d world:%s, world exists",
f.log.Debugf("Frame:setContext", "fid:%s furl:%q ectxid:%d world:%s, overriding existing world",
f.ID(), f.URL(), execCtx.ID(), world)
return

f.executionContexts[world] = nil
f.documentHandle = nil
}

f.executionContexts[world] = execCtx
Expand Down
27 changes: 17 additions & 10 deletions common/frame_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,18 +663,25 @@ func (fs *FrameSession) onExecutionContextCreated(event *cdpruntime.EventExecuti
if err := json.Unmarshal(auxData, &i); err != nil {
k6ext.Panic(fs.ctx, "unmarshaling executionContextCreated event JSON: %w", err)
}
var world executionWorld

frame, ok := fs.manager.getFrameByID(i.FrameID)
if ok {
if i.IsDefault {
world = mainWorld
} else if event.Context.Name == utilityWorldName && !frame.hasContext(utilityWorld) {
// In case of multiple sessions to the same target, there's a race between
// connections so we might end up creating multiple isolated worlds.
// We can use either.
world = utilityWorld
}
if !ok {
fs.logger.Debugf("FrameSession:onExecutionContextCreated:return",
"sid:%v tid:%v ectxid:%d missing frame",
fs.session.ID(), fs.targetID, event.Context.ID)
return
}

var world executionWorld
if i.IsDefault {
world = mainWorld
} else if event.Context.Name == utilityWorldName && !frame.hasContext(utilityWorld) {
// In case of multiple sessions to the same target, there's a race between
// connections so we might end up creating multiple isolated worlds.
// We can use either.
world = utilityWorld
}

if i.Type == "isolated" {
fs.isolatedWorlds[event.Context.Name] = true
}
Expand Down