diff options
Diffstat (limited to 'remote/webdriver-bidi/modules/root/network.sys.mjs')
-rw-r--r-- | remote/webdriver-bidi/modules/root/network.sys.mjs | 457 |
1 files changed, 191 insertions, 266 deletions
diff --git a/remote/webdriver-bidi/modules/root/network.sys.mjs b/remote/webdriver-bidi/modules/root/network.sys.mjs index 6850e3f372..326fa87a02 100644 --- a/remote/webdriver-bidi/modules/root/network.sys.mjs +++ b/remote/webdriver-bidi/modules/root/network.sys.mjs @@ -12,8 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { generateUUID: "chrome://remote/content/shared/UUID.sys.mjs", matchURLPattern: "chrome://remote/content/shared/webdriver/URLPattern.sys.mjs", - notifyNavigationStarted: - "chrome://remote/content/shared/NavigationManager.sys.mjs", NetworkListener: "chrome://remote/content/shared/listeners/NetworkListener.sys.mjs", parseChallengeHeader: @@ -309,7 +307,9 @@ class NetworkModule extends Module { // Set of event names which have active subscriptions this.#subscribedEvents = new Set(); - this.#networkListener = new lazy.NetworkListener(); + this.#networkListener = new lazy.NetworkListener( + this.messageHandler.navigationManager + ); this.#networkListener.on("auth-required", this.#onAuthRequired); this.#networkListener.on("before-request-sent", this.#onBeforeRequestSent); this.#networkListener.on("fetch-error", this.#onFetchError); @@ -549,8 +549,7 @@ class NetworkModule extends Module { ); } - const wrapper = ChannelWrapper.get(request); - wrapper.resume(); + request.wrappedChannel.resume(); resolveBlockedEvent(); } @@ -684,8 +683,7 @@ class NetworkModule extends Module { await authCallbacks.provideAuthCredentials(); } } else { - const wrapper = ChannelWrapper.get(request); - wrapper.resume(); + request.wrappedChannel.resume(); } resolveBlockedEvent(); @@ -803,9 +801,8 @@ class NetworkModule extends Module { ); } - const wrapper = ChannelWrapper.get(request); - wrapper.resume(); - wrapper.cancel( + request.wrappedChannel.resume(); + request.wrappedChannel.cancel( Cr.NS_ERROR_ABORT, Ci.nsILoadInfo.BLOCKING_REASON_WEBDRIVER_BIDI ); @@ -933,8 +930,7 @@ class NetworkModule extends Module { if (phase === InterceptPhase.AuthRequired) { await authCallbacks.provideAuthCredentials(); } else { - const wrapper = ChannelWrapper.get(request); - wrapper.resume(); + request.wrappedChannel.resume(); } resolveBlockedEvent(); @@ -987,11 +983,7 @@ class NetworkModule extends Module { * The response channel. */ #addBlockedRequest(requestId, phase, options = {}) { - const { - authCallbacks, - requestChannel: request, - responseChannel: response, - } = options; + const { authCallbacks, request, response } = options; const { promise: blockedEventPromise, resolve: resolveBlockedEvent } = Promise.withResolvers(); @@ -1117,14 +1109,14 @@ class NetworkModule extends Module { } } - #extractChallenges(responseData) { + #extractChallenges(response) { let headerName; // Using case-insensitive match for header names, so we use the lowercase // version of the "WWW-Authenticate" / "Proxy-Authenticate" strings. - if (responseData.status === 401) { + if (response.status === 401) { headerName = "www-authenticate"; - } else if (responseData.status === 407) { + } else if (response.status === 407) { headerName = "proxy-authenticate"; } else { return null; @@ -1132,10 +1124,10 @@ class NetworkModule extends Module { const challenges = []; - for (const header of responseData.headers) { - if (header.name.toLowerCase() === headerName) { + for (const [name, value] of response.getHeadersList()) { + if (name.toLowerCase() === headerName) { // A single header can contain several challenges. - const headerChallenges = lazy.parseChallengeHeader(header.value); + const headerChallenges = lazy.parseChallengeHeader(value); for (const headerChallenge of headerChallenges) { const realmParam = headerChallenge.params.find( param => param.name == "realm" @@ -1177,7 +1169,7 @@ class NetworkModule extends Module { }; } - #getNetworkIntercepts(event, requestData, contextId) { + #getNetworkIntercepts(event, request, topContextId) { const intercepts = []; let phase; @@ -1197,17 +1189,11 @@ class NetworkModule extends Module { return intercepts; } - // Retrieve the top browsing context id for this network event. - const browsingContext = lazy.TabManager.getBrowsingContextById(contextId); - const topLevelContextId = lazy.TabManager.getIdForBrowsingContext( - browsingContext.top - ); - - const url = requestData.url; + const url = request.serializedURL; for (const [interceptId, intercept] of this.#interceptMap) { if ( intercept.contexts !== null && - !intercept.contexts.includes(topLevelContextId) + !intercept.contexts.includes(topContextId) ) { // Skip this intercept if the event's context does not match the list // of contexts for this intercept. @@ -1228,31 +1214,96 @@ class NetworkModule extends Module { return intercepts; } - #getNavigationId(eventName, isNavigationRequest, browsingContext, url) { - if (!isNavigationRequest) { - // Not a navigation request return null. - return null; + #getRequestData(request) { + const requestId = request.requestId; + + // "Let url be the result of running the URL serializer with request’s URL" + // request.serializedURL is already serialized. + const url = request.serializedURL; + const method = request.method; + + const bodySize = request.postDataSize; + const headersSize = request.headersSize; + const headers = []; + const cookies = []; + + for (const [name, value] of request.getHeadersList()) { + headers.push(this.#serializeHeader(name, value)); + if (name.toLowerCase() == "cookie") { + // TODO: Retrieve the actual cookies from the cookie store. + const headerCookies = value.split(";"); + for (const cookie of headerCookies) { + const equal = cookie.indexOf("="); + const cookieName = cookie.substr(0, equal); + const cookieValue = cookie.substr(equal + 1); + const serializedCookie = this.#serializeHeader( + unescape(cookieName.trim()), + unescape(cookieValue.trim()) + ); + cookies.push(serializedCookie); + } + } } - let navigation = - this.messageHandler.navigationManager.getNavigationForBrowsingContext( - browsingContext - ); + const timings = request.getFetchTimings(); - // `onBeforeRequestSent` might be too early for the NavigationManager. - // If there is no ongoing navigation, create one ourselves. - // TODO: Bug 1835704 to detect navigations earlier and avoid this. - if ( - eventName === "network.beforeRequestSent" && - (!navigation || navigation.finished) - ) { - navigation = lazy.notifyNavigationStarted({ - contextDetails: { context: browsingContext }, - url, - }); + return { + request: requestId, + url, + method, + bodySize, + headersSize, + headers, + cookies, + timings, + }; + } + + #getResponseContentInfo(response) { + return { + size: response.decodedBodySize, + }; + } + + #getResponseData(response) { + const url = response.serializedURL; + const protocol = response.protocol; + const status = response.status; + const statusText = response.statusMessage; + // TODO: Ideally we should have a `isCacheStateLocal` getter + // const fromCache = response.isCacheStateLocal(); + const fromCache = response.fromCache; + const mimeType = response.getComputedMimeType(); + const headers = []; + for (const [name, value] of response.getHeadersList()) { + headers.push(this.#serializeHeader(name, value)); + } + + const bytesReceived = response.totalTransmittedSize; + const headersSize = response.headersTransmittedSize; + const bodySize = response.encodedBodySize; + const content = this.#getResponseContentInfo(response); + const authChallenges = this.#extractChallenges(response); + + const params = { + url, + protocol, + status, + statusText, + fromCache, + headers, + mimeType, + bytesReceived, + headersSize, + bodySize, + content, + }; + + if (authChallenges !== null) { + params.authChallenges = authChallenges; } - return navigation ? navigation.navigationId : null; + return params; } #getSuspendMarkerText(requestData, phase) { @@ -1260,21 +1311,13 @@ class NetworkModule extends Module { } #onAuthRequired = (name, data) => { - const { - authCallbacks, - contextId, - isNavigationRequest, - redirectCount, - requestChannel, - requestData, - responseChannel, - responseData, - timestamp, - } = data; + const { authCallbacks, request, response } = data; let isBlocked = false; try { - const browsingContext = lazy.TabManager.getBrowsingContextById(contextId); + const browsingContext = lazy.TabManager.getBrowsingContextById( + request.contextId + ); if (!browsingContext) { // Do not emit events if the context id does not match any existing // browsing context. @@ -1283,18 +1326,9 @@ class NetworkModule extends Module { const protocolEventName = "network.authRequired"; - // Process the navigation to create potentially missing navigation ids - // before the early return below. - const navigation = this.#getNavigationId( - protocolEventName, - isNavigationRequest, - browsingContext, - requestData.url - ); - const isListening = this.messageHandler.eventsDispatcher.hasListener( protocolEventName, - { contextId } + { contextId: request.contextId } ); if (!isListening) { // If there are no listeners subscribed to this event and this context, @@ -1302,23 +1336,16 @@ class NetworkModule extends Module { return; } - const baseParameters = this.#processNetworkEvent(protocolEventName, { - contextId, - navigation, - redirectCount, - requestData, - timestamp, - }); + const baseParameters = this.#processNetworkEvent( + protocolEventName, + request + ); - const authRequiredEvent = this.#serializeNetworkEvent({ + const responseData = this.#getResponseData(response); + const authRequiredEvent = { ...baseParameters, response: responseData, - }); - - const authChallenges = this.#extractChallenges(responseData); - // authChallenges should never be null for a request which triggered an - // authRequired event. - authRequiredEvent.response.authChallenges = authChallenges; + }; this.emitEvent( protocolEventName, @@ -1337,8 +1364,8 @@ class NetworkModule extends Module { InterceptPhase.AuthRequired, { authCallbacks, - requestChannel, - responseChannel, + request, + response, } ); } @@ -1352,16 +1379,11 @@ class NetworkModule extends Module { }; #onBeforeRequestSent = (name, data) => { - const { - contextId, - isNavigationRequest, - redirectCount, - requestChannel, - requestData, - timestamp, - } = data; + const { request } = data; - const browsingContext = lazy.TabManager.getBrowsingContextById(contextId); + const browsingContext = lazy.TabManager.getBrowsingContextById( + request.contextId + ); if (!browsingContext) { // Do not emit events if the context id does not match any existing // browsing context. @@ -1371,15 +1393,6 @@ class NetworkModule extends Module { const internalEventName = "network._beforeRequestSent"; const protocolEventName = "network.beforeRequestSent"; - // Process the navigation to create potentially missing navigation ids - // before the early return below. - const navigation = this.#getNavigationId( - protocolEventName, - isNavigationRequest, - browsingContext, - requestData.url - ); - // Always emit internal events, they are used to support the browsingContext // navigate command. // Bug 1861922: Replace internal events with a Network listener helper @@ -1387,15 +1400,15 @@ class NetworkModule extends Module { this.emitEvent( internalEventName, { - navigation, - url: requestData.url, + navigation: request.navigationId, + url: request.serializedURL, }, this.#getContextInfo(browsingContext) ); const isListening = this.messageHandler.eventsDispatcher.hasListener( protocolEventName, - { contextId } + { contextId: request.contextId } ); if (!isListening) { // If there are no listeners subscribed to this event and this context, @@ -1403,23 +1416,20 @@ class NetworkModule extends Module { return; } - const baseParameters = this.#processNetworkEvent(protocolEventName, { - contextId, - navigation, - redirectCount, - requestData, - timestamp, - }); + const baseParameters = this.#processNetworkEvent( + protocolEventName, + request + ); // Bug 1805479: Handle the initiator, including stacktrace details. const initiator = { type: InitiatorType.Other, }; - const beforeRequestSentEvent = this.#serializeNetworkEvent({ + const beforeRequestSentEvent = { ...baseParameters, initiator, - }); + }; this.emitEvent( protocolEventName, @@ -1430,32 +1440,26 @@ class NetworkModule extends Module { if (beforeRequestSentEvent.isBlocked) { // TODO: Requests suspended in beforeRequestSent still reach the server at // the moment. https://bugzilla.mozilla.org/show_bug.cgi?id=1849686 - const wrapper = ChannelWrapper.get(requestChannel); - wrapper.suspend( - this.#getSuspendMarkerText(requestData, "beforeRequestSent") + request.wrappedChannel.suspend( + this.#getSuspendMarkerText(request, "beforeRequestSent") ); this.#addBlockedRequest( beforeRequestSentEvent.request.request, InterceptPhase.BeforeRequestSent, { - requestChannel, + request, } ); } }; #onFetchError = (name, data) => { - const { - contextId, - errorText, - isNavigationRequest, - redirectCount, - requestData, - timestamp, - } = data; + const { request } = data; - const browsingContext = lazy.TabManager.getBrowsingContextById(contextId); + const browsingContext = lazy.TabManager.getBrowsingContextById( + request.contextId + ); if (!browsingContext) { // Do not emit events if the context id does not match any existing // browsing context. @@ -1465,15 +1469,6 @@ class NetworkModule extends Module { const internalEventName = "network._fetchError"; const protocolEventName = "network.fetchError"; - // Process the navigation to create potentially missing navigation ids - // before the early return below. - const navigation = this.#getNavigationId( - protocolEventName, - isNavigationRequest, - browsingContext, - requestData.url - ); - // Always emit internal events, they are used to support the browsingContext // navigate command. // Bug 1861922: Replace internal events with a Network listener helper @@ -1481,15 +1476,15 @@ class NetworkModule extends Module { this.emitEvent( internalEventName, { - navigation, - url: requestData.url, + navigation: request.navigationId, + url: request.serializedURL, }, this.#getContextInfo(browsingContext) ); const isListening = this.messageHandler.eventsDispatcher.hasListener( protocolEventName, - { contextId } + { contextId: request.contextId } ); if (!isListening) { // If there are no listeners subscribed to this event and this context, @@ -1497,18 +1492,15 @@ class NetworkModule extends Module { return; } - const baseParameters = this.#processNetworkEvent(protocolEventName, { - contextId, - navigation, - redirectCount, - requestData, - timestamp, - }); + const baseParameters = this.#processNetworkEvent( + protocolEventName, + request + ); - const fetchErrorEvent = this.#serializeNetworkEvent({ + const fetchErrorEvent = { ...baseParameters, - errorText, - }); + errorText: request.errorText, + }; this.emitEvent( protocolEventName, @@ -1518,18 +1510,11 @@ class NetworkModule extends Module { }; #onResponseEvent = (name, data) => { - const { - contextId, - isNavigationRequest, - redirectCount, - requestChannel, - requestData, - responseChannel, - responseData, - timestamp, - } = data; + const { request, response } = data; - const browsingContext = lazy.TabManager.getBrowsingContextById(contextId); + const browsingContext = lazy.TabManager.getBrowsingContextById( + request.contextId + ); if (!browsingContext) { // Do not emit events if the context id does not match any existing // browsing context. @@ -1546,15 +1531,6 @@ class NetworkModule extends Module { ? "network._responseStarted" : "network._responseCompleted"; - // Process the navigation to create potentially missing navigation ids - // before the early return below. - const navigation = this.#getNavigationId( - protocolEventName, - isNavigationRequest, - browsingContext, - requestData.url - ); - // Always emit internal events, they are used to support the browsingContext // navigate command. // Bug 1861922: Replace internal events with a Network listener helper @@ -1562,15 +1538,15 @@ class NetworkModule extends Module { this.emitEvent( internalEventName, { - navigation, - url: requestData.url, + navigation: request.navigationId, + url: request.serializedURL, }, this.#getContextInfo(browsingContext) ); const isListening = this.messageHandler.eventsDispatcher.hasListener( protocolEventName, - { contextId } + { contextId: request.contextId } ); if (!isListening) { // If there are no listeners subscribed to this event and this context, @@ -1578,23 +1554,17 @@ class NetworkModule extends Module { return; } - const baseParameters = this.#processNetworkEvent(protocolEventName, { - contextId, - navigation, - redirectCount, - requestData, - timestamp, - }); + const baseParameters = this.#processNetworkEvent( + protocolEventName, + request + ); - const responseEvent = this.#serializeNetworkEvent({ + const responseData = this.#getResponseData(response); + + const responseEvent = { ...baseParameters, response: responseData, - }); - - const authChallenges = this.#extractChallenges(responseData); - if (authChallenges !== null) { - responseEvent.response.authChallenges = authChallenges; - } + }; this.emitEvent( protocolEventName, @@ -1606,51 +1576,40 @@ class NetworkModule extends Module { protocolEventName === "network.responseStarted" && responseEvent.isBlocked ) { - const wrapper = ChannelWrapper.get(requestChannel); - wrapper.suspend( - this.#getSuspendMarkerText(requestData, "responseStarted") + request.wrappedChannel.suspend( + this.#getSuspendMarkerText(request, "responseStarted") ); this.#addBlockedRequest( responseEvent.request.request, InterceptPhase.ResponseStarted, { - requestChannel, - responseChannel, + request, + response, } ); } }; - /** - * Process the network event data for a given network event name and create - * the corresponding base parameters. - * - * @param {string} eventName - * One of the supported network event names. - * @param {object} data - * @param {string} data.contextId - * The browsing context id for the network event. - * @param {string|null} data.navigation - * The navigation id if this is a network event for a navigation request. - * @param {number} data.redirectCount - * The redirect count for the network event. - * @param {RequestData} data.requestData - * The network.RequestData information for the network event. - * @param {number} data.timestamp - * The timestamp when the network event was created. - */ - #processNetworkEvent(eventName, data) { - const { contextId, navigation, redirectCount, requestData, timestamp } = - data; - const intercepts = this.#getNetworkIntercepts( - eventName, - requestData, - contextId - ); - const isBlocked = !!intercepts.length; + #processNetworkEvent(event, request) { + const requestData = this.#getRequestData(request); + const navigation = request.navigationId; + let contextId = null; + let topContextId = null; + if (request.contextId) { + // Retrieve the top browsing context id for this network event. + contextId = request.contextId; + const browsingContext = lazy.TabManager.getBrowsingContextById(contextId); + topContextId = lazy.TabManager.getIdForBrowsingContext( + browsingContext.top + ); + } - const baseParameters = { + const intercepts = this.#getNetworkIntercepts(event, request, topContextId); + const redirectCount = request.redirectCount; + const timestamp = Date.now(); + const isBlocked = !!intercepts.length; + const params = { context: contextId, isBlocked, navigation, @@ -1660,51 +1619,17 @@ class NetworkModule extends Module { }; if (isBlocked) { - baseParameters.intercepts = intercepts; + params.intercepts = intercepts; } - return baseParameters; - } - - #serializeHeadersOrCookies(headersOrCookies) { - return headersOrCookies.map(item => ({ - name: item.name, - value: this.#serializeStringAsBytesValue(item.value), - })); + return params; } - /** - * Serialize in-place all cookies and headers arrays found in a given network - * event payload. - * - * @param {object} networkEvent - * The network event parameters object to serialize. - * @returns {object} - * The serialized network event parameters. - */ - #serializeNetworkEvent(networkEvent) { - // Make a shallow copy of networkEvent before serializing the headers and - // cookies arrays in request/response. - const serialized = { ...networkEvent }; - - // Make a shallow copy of the request data. - serialized.request = { ...networkEvent.request }; - serialized.request.cookies = this.#serializeHeadersOrCookies( - networkEvent.request.cookies - ); - serialized.request.headers = this.#serializeHeadersOrCookies( - networkEvent.request.headers - ); - - if (networkEvent.response?.headers) { - // Make a shallow copy of the response data. - serialized.response = { ...networkEvent.response }; - serialized.response.headers = this.#serializeHeadersOrCookies( - networkEvent.response.headers - ); - } - - return serialized; + #serializeHeader(name, value) { + return { + name, + value: this.#serializeStringAsBytesValue(value), + }; } /** |