chore: fix bidi/core navigation (#11878)

This commit is contained in:
jrandolf 2024-02-08 15:22:17 +01:00 committed by GitHub
parent 8a9fb1051a
commit bfcd65d2f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 65 additions and 37 deletions

View File

@ -210,7 +210,16 @@ export class BrowsingContext extends EventEmitter<{
} }
this.#url = info.url; this.#url = info.url;
this.#requests.clear(); for (const [id, request] of this.#requests) {
if (request.disposed) {
this.#requests.delete(id);
}
}
// If the navigation hasn't finished, then this is nested navigation. The
// current navigation will handle this.
if (this.#navigation !== undefined && !this.#navigation.disposed) {
return;
}
// Note the navigation ID is null for this event. // Note the navigation ID is null for this event.
this.#navigation = Navigation.from(this); this.#navigation = Navigation.from(this);
@ -232,10 +241,10 @@ export class BrowsingContext extends EventEmitter<{
if (event.context !== this.id) { if (event.context !== this.id) {
return; return;
} }
// Means the request is a redirect. This is handled in Request.
if (this.#requests.has(event.request.request)) { if (this.#requests.has(event.request.request)) {
return; return;
} }
const request = Request.from(this, event); const request = Request.from(this, event);
this.#requests.set(request.id, request); this.#requests.set(request.id, request);
this.emit('request', {request}); this.emit('request', {request});
@ -353,33 +362,23 @@ export class BrowsingContext extends EventEmitter<{
async navigate( async navigate(
url: string, url: string,
wait?: Bidi.BrowsingContext.ReadinessState wait?: Bidi.BrowsingContext.ReadinessState
): Promise<Navigation> { ): Promise<void> {
await this.#session.send('browsingContext.navigate', { await this.#session.send('browsingContext.navigate', {
context: this.id, context: this.id,
url, url,
wait, wait,
}); });
return await new Promise(resolve => {
this.once('navigation', ({navigation}) => {
resolve(navigation);
});
});
} }
@throwIfDisposed<BrowsingContext>(context => { @throwIfDisposed<BrowsingContext>(context => {
// SAFETY: Disposal implies this exists. // SAFETY: Disposal implies this exists.
return context.#reason!; return context.#reason!;
}) })
async reload(options: ReloadOptions = {}): Promise<Navigation> { async reload(options: ReloadOptions = {}): Promise<void> {
await this.#session.send('browsingContext.reload', { await this.#session.send('browsingContext.reload', {
context: this.id, context: this.id,
...options, ...options,
}); });
return await new Promise(resolve => {
this.once('navigation', ({navigation}) => {
resolve(navigation);
});
});
} }
@throwIfDisposed<BrowsingContext>(context => { @throwIfDisposed<BrowsingContext>(context => {

View File

@ -41,9 +41,10 @@ export class Navigation extends EventEmitter<{
// keep-sorted start // keep-sorted start
#request: Request | undefined; #request: Request | undefined;
#navigation: Navigation | undefined;
readonly #browsingContext: BrowsingContext; readonly #browsingContext: BrowsingContext;
readonly #disposables = new DisposableStack(); readonly #disposables = new DisposableStack();
readonly #id = new Deferred<string>(); readonly #id = new Deferred<string | null>();
// keep-sorted end // keep-sorted end
private constructor(context: BrowsingContext) { private constructor(context: BrowsingContext) {
@ -65,31 +66,48 @@ export class Navigation extends EventEmitter<{
this.dispose(); this.dispose();
}); });
this.#browsingContext.on('request', ({request}) => { browsingContextEmitter.on('request', ({request}) => {
if (request.navigation === this.#id.value()) { if (
request.navigation === undefined ||
this.#request !== undefined ||
// If a request with a navigation ID comes in, then the navigation ID is
// for this navigation.
!this.#matches(request.navigation)
) {
return;
}
this.#request = request; this.#request = request;
this.emit('request', request); this.emit('request', request);
}
}); });
const sessionEmitter = this.#disposables.use( const sessionEmitter = this.#disposables.use(
new EventEmitter(this.#session) new EventEmitter(this.#session)
); );
// To get the navigation ID if any. sessionEmitter.on('browsingContext.navigationStarted', info => {
if (
info.context !== this.#browsingContext.id ||
this.#navigation !== undefined
) {
return;
}
this.#navigation = Navigation.from(this.#browsingContext);
});
for (const eventName of [ for (const eventName of [
'browsingContext.domContentLoaded', 'browsingContext.domContentLoaded',
'browsingContext.load', 'browsingContext.load',
] as const) { ] as const) {
sessionEmitter.on(eventName, info => { sessionEmitter.on(eventName, info => {
if (info.context !== this.#browsingContext.id) { if (
info.context !== this.#browsingContext.id ||
info.navigation === null ||
!this.#matches(info.navigation)
) {
return; return;
} }
if (!info.navigation) {
return; this.dispose();
}
if (!this.#id.resolved()) {
this.#id.resolve(info.navigation);
}
}); });
} }
@ -99,18 +117,15 @@ export class Navigation extends EventEmitter<{
['browsingContext.navigationAborted', 'aborted'], ['browsingContext.navigationAborted', 'aborted'],
] as const) { ] as const) {
sessionEmitter.on(eventName, info => { sessionEmitter.on(eventName, info => {
if (info.context !== this.#browsingContext.id) { if (
return; info.context !== this.#browsingContext.id ||
} // Note we don't check if `navigation` is null since `null` means the
if (!info.navigation) { // fragment navigated.
return; !this.#matches(info.navigation)
} ) {
if (!this.#id.resolved()) {
this.#id.resolve(info.navigation);
}
if (this.#id.value() !== info.navigation) {
return; return;
} }
this.emit(event, { this.emit(event, {
url: info.url, url: info.url,
timestamp: new Date(info.timestamp), timestamp: new Date(info.timestamp),
@ -120,6 +135,17 @@ export class Navigation extends EventEmitter<{
} }
} }
#matches(navigation: string | null): boolean {
if (this.#navigation !== undefined && !this.#navigation.disposed) {
return false;
}
if (!this.#id.resolved()) {
this.#id.resolve(navigation);
return true;
}
return this.#id.value() === navigation;
}
// keep-sorted start block=yes // keep-sorted start block=yes
get #session() { get #session() {
return this.#browsingContext.userContext.browser.session; return this.#browsingContext.userContext.browser.session;
@ -130,6 +156,9 @@ export class Navigation extends EventEmitter<{
get request(): Request | undefined { get request(): Request | undefined {
return this.#request; return this.#request;
} }
get navigation(): Navigation | undefined {
return this.#navigation;
}
// keep-sorted end // keep-sorted end
@inertIfDisposed @inertIfDisposed