@@ -9,14 +9,15 @@ import (
99 "slices"
1010 "strings"
1111 "sync"
12+ "sync/atomic"
1213
1314 "github.com/playwright-community/playwright-go/internal/safe"
1415)
1516
1617type browserContextImpl struct {
1718 channelOwner
1819 timeoutSettings * timeoutSettings
19- closeWasCalled bool
20+ closeWasCalled atomic. Bool
2021 options * BrowserNewContextOptions
2122 pages []Page
2223 routes []* routeHandlerEntry
@@ -91,7 +92,7 @@ func (b *browserContextImpl) NewCDPSession(page interface{}) (CDPSession, error)
9192 return nil , err
9293 }
9394
94- cdpSession := fromChannel (channel ).(* cdpSessionImpl )
95+ cdpSession := fromChannelWithConnection (channel , b . connection ).(* cdpSessionImpl )
9596
9697 return cdpSession , nil
9798}
@@ -104,7 +105,7 @@ func (b *browserContextImpl) NewPage() (Page, error) {
104105 if err != nil {
105106 return nil , err
106107 }
107- return fromChannel (channel ).(* pageImpl ), nil
108+ return fromChannelWithConnection (channel , b . connection ).(* pageImpl ), nil
108109}
109110
110111func (b * browserContextImpl ) Cookies (urls ... string ) ([]Cookie , error ) {
@@ -411,13 +412,13 @@ func (b *browserContextImpl) ExpectPage(cb func() error, options ...BrowserConte
411412}
412413
413414func (b * browserContextImpl ) Close (options ... BrowserContextCloseOptions ) error {
414- if b .closeWasCalled {
415+ if b .closeWasCalled . Load () {
415416 return nil
416417 }
417418 if len (options ) == 1 {
418419 b .closeReason = options [0 ].Reason
419420 }
420- b .closeWasCalled = true
421+ b .closeWasCalled . Store ( true )
421422
422423 _ , err := b .channel .connection .WrapAPICall (func () (interface {}, error ) {
423424 return nil , b .request .Dispose (APIRequestContextDisposeOptions {
@@ -438,7 +439,7 @@ func (b *browserContextImpl) Close(options ...BrowserContextCloseOptions) error
438439 if err != nil {
439440 return nil , err
440441 }
441- artifact := fromChannel (response ).(* artifactImpl )
442+ artifact := fromChannelWithConnection (response , b . connection ).(* artifactImpl )
442443 // Server side will compress artifact if content is attach or if file is .zip.
443444 needCompressed := strings .HasSuffix (strings .ToLower (harMetaData .Path ), ".zip" )
444445 if ! needCompressed && harMetaData .Content == HarContentPolicyAttach {
@@ -597,7 +598,7 @@ func (b *browserContextImpl) onRoute(route *routeImpl) {
597598 url := route .Request ().URL ()
598599 for _ , handlerEntry := range routes {
599600 // If the page or the context was closed we stall all requests right away.
600- if (page != nil && page .closeWasCalled ) || b .closeWasCalled {
601+ if (page != nil && page .closeWasCalled . Load ()) || b .closeWasCalled . Load () {
601602 return
602603 }
603604 if ! handlerEntry .Matches (url ) {
@@ -644,7 +645,7 @@ func (b *browserContextImpl) pause() <-chan error {
644645
645646func (b * browserContextImpl ) onBackgroundPage (ev map [string ]interface {}) {
646647 b .Lock ()
647- p := fromChannel (ev ["page" ]).(* pageImpl )
648+ p := fromChannelWithConnection (ev ["page" ], b . connection ).(* pageImpl )
648649 p .browserContext = b
649650 b .backgroundPages = append (b .backgroundPages , p )
650651 b .Unlock ()
@@ -662,17 +663,41 @@ func (b *browserContextImpl) setOptions(options *BrowserNewContextOptions, trace
662663 options = & BrowserNewContextOptions {}
663664 }
664665 b .options = options
665- if b .options != nil && b .options .RecordHarPath != nil {
666- b .harRecorders ["" ] = harRecordingMetadata {
667- Path : * b .options .RecordHarPath ,
668- Content : b .options .RecordHarContent ,
669- }
670- }
671666 if tracesDir != nil {
672667 b .tracing .tracesDir = * tracesDir
673668 }
674669}
675670
671+ // initializeHarFromOptions starts HAR recording if RecordHarPath is set in options.
672+ // This must be called after context creation to properly register the HAR recorder on the server.
673+ func (b * browserContextImpl ) initializeHarFromOptions () error {
674+ if b .options == nil || b .options .RecordHarPath == nil {
675+ return nil
676+ }
677+ path := * b .options .RecordHarPath
678+ // Determine default content policy based on file extension
679+ var content * HarContentPolicy
680+ if strings .HasSuffix (strings .ToLower (path ), ".zip" ) {
681+ content = HarContentPolicyAttach
682+ } else {
683+ content = HarContentPolicyEmbed
684+ }
685+ if b .options .RecordHarContent != nil {
686+ content = b .options .RecordHarContent
687+ } else if b .options .RecordHarOmitContent != nil && * b .options .RecordHarOmitContent {
688+ content = HarContentPolicyOmit
689+ }
690+ mode := HarModeFull
691+ if b .options .RecordHarMode != nil {
692+ mode = b .options .RecordHarMode
693+ }
694+ return b .recordIntoHar (path , browserContextRecordIntoHarOptions {
695+ URL : b .options .RecordHarURLFilter ,
696+ UpdateContent : content ,
697+ UpdateMode : mode ,
698+ })
699+ }
700+
676701func (b * browserContextImpl ) BackgroundPages () []Page {
677702 b .Lock ()
678703 defer b .Unlock ()
@@ -784,33 +809,49 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
784809 }
785810 bt .createChannelOwner (bt , parent , objectType , guid , initializer )
786811 if parent .objectType == "Browser" {
787- bt .browser = fromChannel (parent .channel ).(* browserImpl )
812+ bt .browser = fromChannelWithConnection (parent .channel , bt . connection ).(* browserImpl )
788813 bt .browser .contexts = append (bt .browser .contexts , bt )
789814 }
790- bt .tracing = fromChannel (initializer ["tracing" ]).(* tracingImpl )
791- bt .request = fromChannel (initializer ["requestContext" ]).(* apiRequestContextImpl )
815+ bt .tracing = fromChannelWithConnection (initializer ["tracing" ], bt . connection ).(* tracingImpl )
816+ bt .request = fromChannelWithConnection (initializer ["requestContext" ], bt . connection ).(* apiRequestContextImpl )
792817 bt .clock = newClock (bt )
818+
819+ // Register this context with the selectors manager for custom selector engines
820+ if bt .browser != nil && bt .browser .browserType != nil {
821+ if browserType , ok := bt .browser .browserType .(* browserTypeImpl ); ok && browserType .playwright != nil {
822+ browserType .playwright .Selectors .(* selectorsImpl ).addContext (bt )
823+ }
824+ }
825+
793826 bt .channel .On ("bindingCall" , func (params map [string ]interface {}) {
794- bt .onBinding (fromChannel (params ["binding" ]).(* bindingCallImpl ))
827+ bt .onBinding (fromChannelWithConnection (params ["binding" ], bt . connection ).(* bindingCallImpl ))
795828 })
796829
797- bt .channel .On ("close" , bt .onClose )
830+ bt .channel .On ("close" , func () {
831+ // Unregister this context from the selectors manager
832+ if bt .browser != nil && bt .browser .browserType != nil {
833+ if browserType , ok := bt .browser .browserType .(* browserTypeImpl ); ok && browserType .playwright != nil {
834+ browserType .playwright .Selectors .(* selectorsImpl ).removeContext (bt )
835+ }
836+ }
837+ bt .onClose ()
838+ })
798839 bt .channel .On ("page" , func (payload map [string ]interface {}) {
799- bt .onPage (fromChannel (payload ["page" ]).(* pageImpl ))
840+ bt .onPage (fromChannelWithConnection (payload ["page" ], bt . connection ).(* pageImpl ))
800841 })
801842 bt .channel .On ("route" , func (params map [string ]interface {}) {
802843 bt .channel .CreateTask (func () {
803- bt .onRoute (fromChannel (params ["route" ]).(* routeImpl ))
844+ bt .onRoute (fromChannelWithConnection (params ["route" ], bt . connection ).(* routeImpl ))
804845 })
805846 })
806847 bt .channel .On ("webSocketRoute" , func (params map [string ]interface {}) {
807848 bt .channel .CreateTask (func () {
808- bt .onWebSocketRoute (fromChannel (params ["webSocketRoute" ]).(* webSocketRouteImpl ))
849+ bt .onWebSocketRoute (fromChannelWithConnection (params ["webSocketRoute" ], bt . connection ).(* webSocketRouteImpl ))
809850 })
810851 })
811852 bt .channel .On ("backgroundPage" , bt .onBackgroundPage )
812853 bt .channel .On ("serviceWorker" , func (params map [string ]interface {}) {
813- bt .onServiceWorker (fromChannel (params ["worker" ]).(* workerImpl ))
854+ bt .onServiceWorker (fromChannelWithConnection (params ["worker" ], bt . connection ).(* workerImpl ))
814855 })
815856 bt .channel .On ("console" , func (ev map [string ]interface {}) {
816857 message := newConsoleMessage (ev )
@@ -820,7 +861,7 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
820861 }
821862 })
822863 bt .channel .On ("dialog" , func (params map [string ]interface {}) {
823- dialog := fromChannel (params ["dialog" ]).(* dialogImpl )
864+ dialog := fromChannelWithConnection (params ["dialog" ], bt . connection ).(* dialogImpl )
824865 go func () {
825866 hasListeners := bt .Emit ("dialog" , dialog )
826867 page := dialog .page
@@ -857,15 +898,15 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
857898 },
858899 )
859900 bt .channel .On ("request" , func (ev map [string ]interface {}) {
860- request := fromChannel (ev ["request" ]).(* requestImpl )
901+ request := fromChannelWithConnection (ev ["request" ], bt . connection ).(* requestImpl )
861902 page := fromNullableChannel (ev ["page" ])
862903 bt .Emit ("request" , request )
863904 if page != nil {
864905 page .(* pageImpl ).Emit ("request" , request )
865906 }
866907 })
867908 bt .channel .On ("requestFailed" , func (ev map [string ]interface {}) {
868- request := fromChannel (ev ["request" ]).(* requestImpl )
909+ request := fromChannelWithConnection (ev ["request" ], bt . connection ).(* requestImpl )
869910 failureText := ev ["failureText" ]
870911 if failureText != nil {
871912 request .failureText = failureText .(string )
@@ -879,7 +920,7 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
879920 })
880921
881922 bt .channel .On ("requestFinished" , func (ev map [string ]interface {}) {
882- request := fromChannel (ev ["request" ]).(* requestImpl )
923+ request := fromChannelWithConnection (ev ["request" ], bt . connection ).(* requestImpl )
883924 response := fromNullableChannel (ev ["response" ])
884925 page := fromNullableChannel (ev ["page" ])
885926 request .setResponseEndTiming (ev ["responseEndTiming" ].(float64 ))
@@ -892,7 +933,7 @@ func newBrowserContext(parent *channelOwner, objectType string, guid string, ini
892933 }
893934 })
894935 bt .channel .On ("response" , func (ev map [string ]interface {}) {
895- response := fromChannel (ev ["response" ]).(* responseImpl )
936+ response := fromChannelWithConnection (ev ["response" ], bt . connection ).(* responseImpl )
896937 page := fromNullableChannel (ev ["page" ])
897938 bt .Emit ("response" , response )
898939 if page != nil {
0 commit comments