mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore(webdriver): support options in request.continue
(#12155)
This commit is contained in:
parent
b144935789
commit
6edb80b2a5
@ -5,6 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
import type {Protocol} from 'devtools-protocol';
|
import type {Protocol} from 'devtools-protocol';
|
||||||
|
|
||||||
|
import type {ProtocolError} from '../common/Errors.js';
|
||||||
|
import {debugError} from '../common/util.js';
|
||||||
|
|
||||||
import type {CDPSession} from './CDPSession.js';
|
import type {CDPSession} from './CDPSession.js';
|
||||||
import type {Frame} from './Frame.js';
|
import type {Frame} from './Frame.js';
|
||||||
import type {HTTPResponse} from './HTTPResponse.js';
|
import type {HTTPResponse} from './HTTPResponse.js';
|
||||||
@ -513,3 +516,16 @@ export const STATUS_TEXTS: Record<string, string> = {
|
|||||||
'510': 'Not Extended',
|
'510': 'Not Extended',
|
||||||
'511': 'Network Authentication Required',
|
'511': 'Network Authentication Required',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function handleError(error: ProtocolError): void {
|
||||||
|
if (error.originalMessage.includes('Invalid header')) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
// In certain cases, protocol will return error if the request was
|
||||||
|
// already canceled or the page was closed. We should tolerate these
|
||||||
|
// errors.
|
||||||
|
debugError(error);
|
||||||
|
}
|
||||||
|
@ -14,10 +14,10 @@ import {
|
|||||||
HTTPRequest,
|
HTTPRequest,
|
||||||
STATUS_TEXTS,
|
STATUS_TEXTS,
|
||||||
type ResourceType,
|
type ResourceType,
|
||||||
|
handleError,
|
||||||
} from '../api/HTTPRequest.js';
|
} from '../api/HTTPRequest.js';
|
||||||
import {PageEvent} from '../api/Page.js';
|
import {PageEvent} from '../api/Page.js';
|
||||||
import {UnsupportedOperation} from '../common/Errors.js';
|
import {UnsupportedOperation} from '../common/Errors.js';
|
||||||
import {isString} from '../common/util.js';
|
|
||||||
|
|
||||||
import type {Request} from './core/Request.js';
|
import type {Request} from './core/Request.js';
|
||||||
import type {BidiFrame} from './Frame.js';
|
import type {BidiFrame} from './Frame.js';
|
||||||
@ -148,9 +148,33 @@ export class BidiHTTPRequest extends HTTPRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async continue(
|
override async continue(
|
||||||
_overrides: ContinueRequestOverrides = {}
|
overrides: ContinueRequestOverrides = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return await this.#request.continueRequest();
|
if (!this.#request.isBlocked) {
|
||||||
|
throw new Error('Request Interception is not enabled!');
|
||||||
|
}
|
||||||
|
// Request interception is not supported for data: urls.
|
||||||
|
if (this.url().startsWith('data:')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers: Bidi.Network.Header[] = getBidiHeaders(overrides.headers);
|
||||||
|
|
||||||
|
return await this.#request
|
||||||
|
.continueRequest({
|
||||||
|
url: overrides.url,
|
||||||
|
method: overrides.method,
|
||||||
|
body: overrides.postData
|
||||||
|
? {
|
||||||
|
type: 'base64',
|
||||||
|
value: btoa(overrides.postData),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
headers: headers.length > 0 ? headers : undefined,
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
return handleError(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
override responseForRequest(): never {
|
override responseForRequest(): never {
|
||||||
@ -174,6 +198,13 @@ export class BidiHTTPRequest extends HTTPRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async abort(): Promise<void> {
|
override async abort(): Promise<void> {
|
||||||
|
if (!this.#request.isBlocked) {
|
||||||
|
throw new Error('Request Interception is not enabled!');
|
||||||
|
}
|
||||||
|
// Request interception is not supported for data: urls.
|
||||||
|
if (this.url().startsWith('data:')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return await this.#request.failRequest();
|
return await this.#request.failRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,25 +212,25 @@ export class BidiHTTPRequest extends HTTPRequest {
|
|||||||
response: Partial<ResponseForRequest>,
|
response: Partial<ResponseForRequest>,
|
||||||
_priority?: number
|
_priority?: number
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const responseBody: Buffer | null =
|
if (!this.#request.isBlocked) {
|
||||||
response.body && isString(response.body)
|
throw new Error('Request Interception is not enabled!');
|
||||||
? Buffer.from(response.body)
|
|
||||||
: (response.body as Buffer) || null;
|
|
||||||
|
|
||||||
const headers: Bidi.Network.Header[] = [];
|
|
||||||
let hasContentLength = false;
|
|
||||||
for (const [name, value] of Object.entries(response.headers ?? [])) {
|
|
||||||
if (name.toLocaleLowerCase() === 'content-length') {
|
|
||||||
hasContentLength = true;
|
|
||||||
}
|
|
||||||
headers.push({
|
|
||||||
name: name.toLowerCase(),
|
|
||||||
value: {
|
|
||||||
type: 'string',
|
|
||||||
value: String(value),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// Request interception is not supported for data: urls.
|
||||||
|
if (this.url().startsWith('data:')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseBody: string | undefined =
|
||||||
|
response.body && response.body instanceof Uint8Array
|
||||||
|
? response.body.toString('base64')
|
||||||
|
: response.body
|
||||||
|
? btoa(response.body)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const headers: Bidi.Network.Header[] = getBidiHeaders(response.headers);
|
||||||
|
const hasContentLength = headers.some(header => {
|
||||||
|
return header.name === 'content-length';
|
||||||
|
});
|
||||||
|
|
||||||
if (response.contentType) {
|
if (response.contentType) {
|
||||||
headers.push({
|
headers.push({
|
||||||
@ -210,16 +241,17 @@ export class BidiHTTPRequest extends HTTPRequest {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseBody && !hasContentLength) {
|
if (responseBody && !hasContentLength) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
headers.push({
|
headers.push({
|
||||||
name: 'content-length',
|
name: 'content-length',
|
||||||
value: {
|
value: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
value: String(Buffer.byteLength(responseBody)),
|
value: String(encoder.encode(responseBody).byteLength),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = response.status || 200;
|
const status = response.status || 200;
|
||||||
|
|
||||||
return await this.#request.provideResponse({
|
return await this.#request.provideResponse({
|
||||||
@ -229,9 +261,24 @@ export class BidiHTTPRequest extends HTTPRequest {
|
|||||||
body: responseBody
|
body: responseBody
|
||||||
? {
|
? {
|
||||||
type: 'base64',
|
type: 'base64',
|
||||||
value: responseBody.toString('base64'),
|
value: responseBody,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBidiHeaders(rawHeaders?: Record<string, unknown>) {
|
||||||
|
const headers: Bidi.Network.Header[] = [];
|
||||||
|
for (const [name, value] of Object.entries(rawHeaders ?? [])) {
|
||||||
|
headers.push({
|
||||||
|
name: name.toLowerCase(),
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
value: String(value),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
@ -141,29 +141,29 @@ export class Request extends EventEmitter<{
|
|||||||
get url(): string {
|
get url(): string {
|
||||||
return this.#event.request.url;
|
return this.#event.request.url;
|
||||||
}
|
}
|
||||||
|
get isBlocked(): boolean {
|
||||||
|
return this.#event.isBlocked;
|
||||||
|
}
|
||||||
// keep-sorted end
|
// keep-sorted end
|
||||||
|
|
||||||
async continueRequest(): Promise<void> {
|
async continueRequest({
|
||||||
if (!this.#event.isBlocked) {
|
url,
|
||||||
throw new Error('Request Interception is not enabled!');
|
method,
|
||||||
}
|
headers,
|
||||||
// Request interception is not supported for data: urls.
|
cookies,
|
||||||
if (this.url.startsWith('data:')) {
|
body,
|
||||||
return;
|
}: Omit<Bidi.Network.ContinueRequestParameters, 'request'>): Promise<void> {
|
||||||
}
|
|
||||||
await this.#session.send('network.continueRequest', {
|
await this.#session.send('network.continueRequest', {
|
||||||
request: this.id,
|
request: this.id,
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
cookies,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async failRequest(): Promise<void> {
|
async failRequest(): Promise<void> {
|
||||||
if (!this.#event.isBlocked) {
|
|
||||||
throw new Error('Request Interception is not enabled!');
|
|
||||||
}
|
|
||||||
// Request interception is not supported for data: urls.
|
|
||||||
if (this.url.startsWith('data:')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.#session.send('network.failRequest', {
|
await this.#session.send('network.failRequest', {
|
||||||
request: this.id,
|
request: this.id,
|
||||||
});
|
});
|
||||||
@ -175,13 +175,6 @@ export class Request extends EventEmitter<{
|
|||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
}: Omit<Bidi.Network.ProvideResponseParameters, 'request'>): Promise<void> {
|
}: Omit<Bidi.Network.ProvideResponseParameters, 'request'>): Promise<void> {
|
||||||
if (!this.#event.isBlocked) {
|
|
||||||
throw new Error('Request Interception is not enabled!');
|
|
||||||
}
|
|
||||||
// Request interception is not supported for data: urls.
|
|
||||||
if (this.url.startsWith('data:')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.#session.send('network.provideResponse', {
|
await this.#session.send('network.provideResponse', {
|
||||||
request: this.id,
|
request: this.id,
|
||||||
statusCode,
|
statusCode,
|
||||||
|
@ -17,8 +17,8 @@ import {
|
|||||||
type ResourceType,
|
type ResourceType,
|
||||||
type ResponseForRequest,
|
type ResponseForRequest,
|
||||||
STATUS_TEXTS,
|
STATUS_TEXTS,
|
||||||
|
handleError,
|
||||||
} from '../api/HTTPRequest.js';
|
} from '../api/HTTPRequest.js';
|
||||||
import type {ProtocolError} from '../common/Errors.js';
|
|
||||||
import {debugError, isString} from '../common/util.js';
|
import {debugError, isString} from '../common/util.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
|
|
||||||
@ -438,13 +438,3 @@ const errorReasons: Record<ErrorCode, Protocol.Network.ErrorReason> = {
|
|||||||
timedout: 'TimedOut',
|
timedout: 'TimedOut',
|
||||||
failed: 'Failed',
|
failed: 'Failed',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
async function handleError(error: ProtocolError) {
|
|
||||||
if (['Invalid header'].includes(error.originalMessage)) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
// In certain cases, protocol will return error if the request was
|
|
||||||
// already canceled or the page was closed. We should tolerate these
|
|
||||||
// errors.
|
|
||||||
debugError(error);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user