44using Newtonsoft . Json . Linq ;
55using PuppeteerSharp . Helpers ;
66using PuppeteerSharp . Input ;
7+ using PuppeteerSharp . Messaging ;
78
89namespace PuppeteerSharp
910{
1011 /// <inheritdoc cref="PuppeteerSharp.IFrame" />
1112 public class Frame : IFrame , IEnvironment
1213 {
14+ private const string RefererHeaderName = "referer" ;
15+
1316 private Task < ElementHandle > _documentTask ;
1417
1518 internal Frame ( FrameManager frameManager , string frameId , string parentFrameId , CDPSession client )
@@ -56,8 +59,6 @@ internal Frame(FrameManager frameManager, string frameId, string parentFrameId,
5659
5760 internal string ParentId { get ; }
5861
59- internal Frame ParentFrame => FrameManager . FrameTree . GetParentFrame ( Id ) ;
60-
6162 internal FrameManager FrameManager { get ; }
6263
6364 internal string LoaderId { get ; private set ; }
@@ -74,23 +75,86 @@ internal Frame(FrameManager frameManager, string frameId, string parentFrameId,
7475
7576 internal bool HasStartedLoading { get ; private set ; }
7677
78+ private Frame ParentFrame => FrameManager . FrameTree . GetParentFrame ( Id ) ;
79+
7780 /// <inheritdoc/>
78- public Task < IResponse > GoToAsync ( string url , NavigationOptions options )
81+ public async Task < IResponse > GoToAsync ( string url , NavigationOptions options )
7982 {
83+ var ensureNewDocumentNavigation = false ;
84+
8085 if ( options == null )
8186 {
8287 throw new ArgumentNullException ( nameof ( options ) ) ;
8388 }
8489
85- return FrameManager . NavigateFrameAsync ( this , url , options ) ;
90+ var referrer = string . IsNullOrEmpty ( options . Referer )
91+ ? FrameManager . NetworkManager . ExtraHTTPHeaders ? . GetValueOrDefault ( RefererHeaderName )
92+ : options . Referer ;
93+ var referrerPolicy = string . IsNullOrEmpty ( options . ReferrerPolicy )
94+ ? FrameManager . NetworkManager . ExtraHTTPHeaders ? . GetValueOrDefault ( "referer-policy" )
95+ : options . ReferrerPolicy ;
96+ var timeout = options . Timeout ?? FrameManager . TimeoutSettings . NavigationTimeout ;
97+
98+ using var watcher = new LifecycleWatcher ( FrameManager . NetworkManager , this , options . WaitUntil , timeout ) ;
99+ try
100+ {
101+ var navigateTask = NavigateAsync ( ) ;
102+ var task = await Task . WhenAny (
103+ watcher . TerminationTask ,
104+ navigateTask ) . ConfigureAwait ( false ) ;
105+
106+ await task . ConfigureAwait ( false ) ;
107+
108+ task = await Task . WhenAny (
109+ watcher . TerminationTask ,
110+ ensureNewDocumentNavigation ? watcher . NewDocumentNavigationTask : watcher . SameDocumentNavigationTask ) . ConfigureAwait ( false ) ;
111+
112+ await task . ConfigureAwait ( false ) ;
113+ }
114+ catch ( Exception ex )
115+ {
116+ throw new NavigationException ( ex . Message , ex ) ;
117+ }
118+
119+ return watcher . NavigationResponse ;
120+
121+ async Task NavigateAsync ( )
122+ {
123+ var response = await Client . SendAsync < PageNavigateResponse > ( "Page.navigate" , new PageNavigateRequest
124+ {
125+ Url = url ,
126+ Referrer = referrer ?? string . Empty ,
127+ ReferrerPolicy = referrerPolicy ?? string . Empty ,
128+ FrameId = Id ,
129+ } ) . ConfigureAwait ( false ) ;
130+
131+ ensureNewDocumentNavigation = ! string . IsNullOrEmpty ( response . LoaderId ) ;
132+
133+ if ( ! string . IsNullOrEmpty ( response . ErrorText ) && response . ErrorText != "net::ERR_HTTP_RESPONSE_CODE_FAILURE" )
134+ {
135+ throw new NavigationException ( response . ErrorText , url ) ;
136+ }
137+ }
86138 }
87139
88140 /// <inheritdoc/>
89141 public Task < IResponse > GoToAsync ( string url , int ? timeout = null , WaitUntilNavigation [ ] waitUntil = null )
90142 => GoToAsync ( url , new NavigationOptions { Timeout = timeout , WaitUntil = waitUntil } ) ;
91143
92144 /// <inheritdoc/>
93- public Task < IResponse > WaitForNavigationAsync ( NavigationOptions options = null ) => FrameManager . WaitForFrameNavigationAsync ( this , options ) ;
145+ public async Task < IResponse > WaitForNavigationAsync ( NavigationOptions options = null )
146+ {
147+ var timeout = options ? . Timeout ?? FrameManager . TimeoutSettings . NavigationTimeout ;
148+ using var watcher = new LifecycleWatcher ( FrameManager . NetworkManager , this , options ? . WaitUntil , timeout ) ;
149+ var raceTask = await Task . WhenAny (
150+ watcher . NewDocumentNavigationTask ,
151+ watcher . SameDocumentNavigationTask ,
152+ watcher . TerminationTask ) . ConfigureAwait ( false ) ;
153+
154+ await raceTask . ConfigureAwait ( false ) ;
155+
156+ return watcher . NavigationResponse ;
157+ }
94158
95159 /// <inheritdoc/>
96160 public Task < JToken > EvaluateExpressionAsync ( string script ) => MainRealm . EvaluateExpressionAsync ( script ) ;
@@ -373,9 +437,9 @@ await IsolatedRealm.EvaluateFunctionAsync(
373437 }" ,
374438 html ) . ConfigureAwait ( false ) ;
375439
376- using var watcher = new LifecycleWatcher ( FrameManager , this , waitUntil , timeout ) ;
440+ using var watcher = new LifecycleWatcher ( FrameManager . NetworkManager , this , waitUntil , timeout ) ;
377441 var watcherTask = await Task . WhenAny (
378- watcher . TimeoutOrTerminationTask ,
442+ watcher . TerminationTask ,
379443 watcher . LifecycleTask ) . ConfigureAwait ( false ) ;
380444
381445 await watcherTask . ConfigureAwait ( false ) ;
@@ -489,7 +553,7 @@ internal void UpdateClient(CDPSession client)
489553 false ) ;
490554 }
491555
492- internal DeviceRequestPromptManager GetDeviceRequestPromptManager ( )
556+ private DeviceRequestPromptManager GetDeviceRequestPromptManager ( )
493557 {
494558 if ( IsOopFrame )
495559 {
0 commit comments