"use strict"; /* * Copyright 2023 Google LLC. * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ Object.defineProperty(exports, "__esModule", { value: true }); exports.computeHeadersSize = computeHeadersSize; exports.stringToBase64 = stringToBase64; exports.bidiNetworkHeadersFromCdpNetworkHeaders = bidiNetworkHeadersFromCdpNetworkHeaders; exports.bidiNetworkHeadersFromCdpNetworkHeadersEntries = bidiNetworkHeadersFromCdpNetworkHeadersEntries; exports.cdpNetworkHeadersFromBidiNetworkHeaders = cdpNetworkHeadersFromBidiNetworkHeaders; exports.bidiNetworkHeadersFromCdpFetchHeaders = bidiNetworkHeadersFromCdpFetchHeaders; exports.cdpFetchHeadersFromBidiNetworkHeaders = cdpFetchHeadersFromBidiNetworkHeaders; exports.networkHeaderFromCookieHeaders = networkHeaderFromCookieHeaders; exports.cdpAuthChallengeResponseFromBidiAuthContinueWithAuthAction = cdpAuthChallengeResponseFromBidiAuthContinueWithAuthAction; exports.cdpToBiDiCookie = cdpToBiDiCookie; exports.deserializeByteValue = deserializeByteValue; exports.bidiToCdpCookie = bidiToCdpCookie; exports.sameSiteBiDiToCdp = sameSiteBiDiToCdp; exports.isSpecialScheme = isSpecialScheme; exports.matchUrlPattern = matchUrlPattern; exports.bidiBodySizeFromCdpPostDataEntries = bidiBodySizeFromCdpPostDataEntries; exports.getTiming = getTiming; const ErrorResponse_js_1 = require("../../../protocol/ErrorResponse.js"); const base64_js_1 = require("../../../utils/base64.js"); function computeHeadersSize(headers) { const requestHeaders = headers.reduce((acc, header) => { return `${acc}${header.name}: ${header.value.value}\r\n`; }, ''); return new TextEncoder().encode(requestHeaders).length; } function stringToBase64(str) { return typedArrayToBase64(new TextEncoder().encode(str)); } function typedArrayToBase64(typedArray) { // chunkSize should be less V8 limit on number of arguments! // https://github.com/v8/v8/blob/d3de848bea727518aee94dd2fd42ba0b62037a27/src/objects/code.h#L444 const chunkSize = 65534; const chunks = []; for (let i = 0; i < typedArray.length; i += chunkSize) { const chunk = typedArray.subarray(i, i + chunkSize); chunks.push(String.fromCodePoint.apply(null, chunk)); } const binaryString = chunks.join(''); return btoa(binaryString); } /** Converts from CDP Network domain headers to BiDi network headers. */ function bidiNetworkHeadersFromCdpNetworkHeaders(headers) { if (!headers) { return []; } return Object.entries(headers).map(([name, value]) => ({ name, value: { type: 'string', value, }, })); } /** Converts from CDP Fetch domain headers to BiDi network headers. */ function bidiNetworkHeadersFromCdpNetworkHeadersEntries(headers) { if (!headers) { return []; } return headers.map(({ name, value }) => ({ name, value: { type: 'string', value, }, })); } /** Converts from Bidi network headers to CDP Network domain headers. */ function cdpNetworkHeadersFromBidiNetworkHeaders(headers) { if (headers === undefined) { return undefined; } return headers.reduce((result, header) => { // TODO: Distinguish between string and bytes? result[header.name] = header.value.value; return result; }, {}); } /** Converts from CDP Fetch domain header entries to Bidi network headers. */ function bidiNetworkHeadersFromCdpFetchHeaders(headers) { if (!headers) { return []; } return headers.map(({ name, value }) => ({ name, value: { type: 'string', value, }, })); } /** Converts from Bidi network headers to CDP Fetch domain header entries. */ function cdpFetchHeadersFromBidiNetworkHeaders(headers) { if (headers === undefined) { return undefined; } return headers.map(({ name, value }) => ({ name, value: value.value, })); } function networkHeaderFromCookieHeaders(headers) { if (headers === undefined) { return undefined; } const value = headers.reduce((acc, value, index) => { if (index > 0) { acc += ';'; } const cookieValue = value.value.type === 'base64' ? btoa(value.value.value) : value.value.value; acc += `${value.name}=${cookieValue}`; return acc; }, ''); return { name: 'Cookie', value: { type: 'string', value, }, }; } /** Converts from Bidi auth action to CDP auth challenge response. */ function cdpAuthChallengeResponseFromBidiAuthContinueWithAuthAction(action) { switch (action) { case 'default': return 'Default'; case 'cancel': return 'CancelAuth'; case 'provideCredentials': return 'ProvideCredentials'; } } /** * Converts from CDP Network domain cookie to BiDi network cookie. * * https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Cookie * * https://w3c.github.io/webdriver-bidi/#type-network-Cookie */ function cdpToBiDiCookie(cookie) { const result = { name: cookie.name, value: { type: 'string', value: cookie.value }, domain: cookie.domain, path: cookie.path, size: cookie.size, httpOnly: cookie.httpOnly, secure: cookie.secure, sameSite: cookie.sameSite === undefined ? "none" /* Network.SameSite.None */ : sameSiteCdpToBiDi(cookie.sameSite), ...(cookie.expires >= 0 ? { expiry: cookie.expires } : undefined), }; // Extending with CDP-specific properties with `goog:` prefix. result[`goog:session`] = cookie.session; result[`goog:priority`] = cookie.priority; result[`goog:sameParty`] = cookie.sameParty; result[`goog:sourceScheme`] = cookie.sourceScheme; result[`goog:sourcePort`] = cookie.sourcePort; if (cookie.partitionKey !== undefined) { result[`goog:partitionKey`] = cookie.partitionKey; } if (cookie.partitionKeyOpaque !== undefined) { result[`goog:partitionKeyOpaque`] = cookie.partitionKeyOpaque; } return result; } /** * Decodes a byte value to a string. * @param {Network.BytesValue} value * @return {string} */ function deserializeByteValue(value) { if (value.type === 'base64') { return (0, base64_js_1.base64ToString)(value.value); } return value.value; } /** * Converts from BiDi set network cookie params to CDP Network domain cookie. * * https://w3c.github.io/webdriver-bidi/#type-network-Cookie * * https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-CookieParam */ function bidiToCdpCookie(params, partitionKey) { const deserializedValue = deserializeByteValue(params.cookie.value); const result = { name: params.cookie.name, value: deserializedValue, domain: params.cookie.domain, path: params.cookie.path ?? '/', secure: params.cookie.secure ?? false, httpOnly: params.cookie.httpOnly ?? false, ...(partitionKey.sourceOrigin !== undefined && { partitionKey: { hasCrossSiteAncestor: false, // CDP's `partitionKey.topLevelSite` is the BiDi's `partition.sourceOrigin`. topLevelSite: partitionKey.sourceOrigin, }, }), ...(params.cookie.expiry !== undefined && { expires: params.cookie.expiry, }), ...(params.cookie.sameSite !== undefined && { sameSite: sameSiteBiDiToCdp(params.cookie.sameSite), }), }; // Extending with CDP-specific properties with `goog:` prefix. if (params.cookie[`goog:url`] !== undefined) { result.url = params.cookie[`goog:url`]; } if (params.cookie[`goog:priority`] !== undefined) { result.priority = params.cookie[`goog:priority`]; } if (params.cookie[`goog:sameParty`] !== undefined) { result.sameParty = params.cookie[`goog:sameParty`]; } if (params.cookie[`goog:sourceScheme`] !== undefined) { result.sourceScheme = params.cookie[`goog:sourceScheme`]; } if (params.cookie[`goog:sourcePort`] !== undefined) { result.sourcePort = params.cookie[`goog:sourcePort`]; } return result; } function sameSiteCdpToBiDi(sameSite) { switch (sameSite) { case 'Strict': return "strict" /* Network.SameSite.Strict */; case 'None': return "none" /* Network.SameSite.None */; case 'Lax': return "lax" /* Network.SameSite.Lax */; default: // Defaults to `Lax`: // https://web.dev/articles/samesite-cookies-explained#samesitelax_by_default return "lax" /* Network.SameSite.Lax */; } } function sameSiteBiDiToCdp(sameSite) { switch (sameSite) { case "none" /* Network.SameSite.None */: return 'None'; case "strict" /* Network.SameSite.Strict */: return 'Strict'; // Defaults to `Lax`: // https://web.dev/articles/samesite-cookies-explained#samesitelax_by_default case "default" /* Network.SameSite.Default */: case "lax" /* Network.SameSite.Lax */: return 'Lax'; } throw new ErrorResponse_js_1.InvalidArgumentException(`Unknown 'sameSite' value ${sameSite}`); } /** * Returns true if the given protocol is special. * Special protocols are those that have a default port. * * Example inputs: 'http', 'http:' * * @see https://url.spec.whatwg.org/#special-scheme */ function isSpecialScheme(protocol) { return ['ftp', 'file', 'http', 'https', 'ws', 'wss'].includes(protocol.replace(/:$/, '')); } function getScheme(url) { return url.protocol.replace(/:$/, ''); } /** Matches the given URLPattern against the given URL. */ function matchUrlPattern(pattern, url) { // Roughly https://w3c.github.io/webdriver-bidi/#match-url-pattern // plus some differences based on the URL parsing methods. const parsedUrl = new URL(url); if (pattern.protocol !== undefined && pattern.protocol !== getScheme(parsedUrl)) { return false; } if (pattern.hostname !== undefined && pattern.hostname !== parsedUrl.hostname) { return false; } if (pattern.port !== undefined && pattern.port !== parsedUrl.port) { return false; } if (pattern.pathname !== undefined && pattern.pathname !== parsedUrl.pathname) { return false; } if (pattern.search !== undefined && pattern.search !== parsedUrl.search) { return false; } return true; } function bidiBodySizeFromCdpPostDataEntries(entries) { let size = 0; for (const entry of entries) { size += atob(entry.bytes ?? '').length; } return size; } function getTiming(timing, offset = 0) { if (!timing) { return 0; } if (timing <= 0 || timing + offset <= 0) { return 0; } return timing + offset; } //# sourceMappingURL=NetworkUtils.js.map