feat: Add maxRedirects to options of apiRequest.newContext (#35160)
This commit is contained in:
parent
accd7c6c9e
commit
beea7c30c5
|
@ -37,6 +37,13 @@ for all status codes.
|
|||
### option: APIRequest.newContext.ignoreHTTPSErrors = %%-context-option-ignorehttpserrors-%%
|
||||
* since: v1.16
|
||||
|
||||
### option: APIRequest.newContext.maxRedirects
|
||||
* since: v1.52
|
||||
- `maxRedirects` <[int]>
|
||||
|
||||
Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is exceeded.
|
||||
Defaults to `20`. Pass `0` to not follow redirects. This can be overwritten for each request individually.
|
||||
|
||||
### option: APIRequest.newContext.timeout
|
||||
* since: v1.16
|
||||
- `timeout` <[float]>
|
||||
|
|
|
@ -17573,6 +17573,13 @@ export interface APIRequest {
|
|||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to `20`. Pass `0` to not follow redirects. This can be overwritten for each request
|
||||
* individually.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Network proxy settings.
|
||||
*/
|
||||
|
|
|
@ -386,6 +386,7 @@ scheme.PlaywrightNewRequestParams = tObject({
|
|||
passphrase: tOptional(tString),
|
||||
pfx: tOptional(tBinary),
|
||||
}))),
|
||||
maxRedirects: tOptional(tNumber),
|
||||
httpCredentials: tOptional(tObject({
|
||||
username: tString,
|
||||
password: tString,
|
||||
|
|
|
@ -56,6 +56,7 @@ type FetchRequestOptions = {
|
|||
proxy?: ProxySettings;
|
||||
timeoutSettings: TimeoutSettings;
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
maxRedirects?: number;
|
||||
baseURL?: string;
|
||||
clientCertificates?: types.BrowserContextOptions['clientCertificates'];
|
||||
};
|
||||
|
@ -185,6 +186,8 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
if (proxy && proxy.server !== 'per-context' && !shouldBypassProxy(requestUrl, proxy.bypass))
|
||||
agent = createProxyAgent(proxy);
|
||||
|
||||
let maxRedirects = params.maxRedirects ?? (defaults.maxRedirects ?? 20);
|
||||
maxRedirects = maxRedirects === 0 ? -1 : maxRedirects;
|
||||
|
||||
const timeout = defaults.timeoutSettings.timeout(params);
|
||||
const deadline = timeout && (monotonicTime() + timeout);
|
||||
|
@ -193,7 +196,7 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
method,
|
||||
headers,
|
||||
agent,
|
||||
maxRedirects: params.maxRedirects === 0 ? -1 : params.maxRedirects === undefined ? 20 : params.maxRedirects,
|
||||
maxRedirects,
|
||||
timeout,
|
||||
deadline,
|
||||
...getMatchingTLSOptionsForOrigin(this._defaultOptions().clientCertificates, requestUrl.origin),
|
||||
|
@ -371,7 +374,7 @@ export abstract class APIRequestContext extends SdkObject {
|
|||
}
|
||||
|
||||
if (redirectStatus.includes(response.statusCode!) && options.maxRedirects >= 0) {
|
||||
if (!options.maxRedirects) {
|
||||
if (options.maxRedirects === 0) {
|
||||
reject(new Error('Max redirect count exceeded'));
|
||||
request.destroy();
|
||||
return;
|
||||
|
@ -662,6 +665,7 @@ export class GlobalAPIRequestContext extends APIRequestContext {
|
|||
extraHTTPHeaders: options.extraHTTPHeaders,
|
||||
failOnStatusCode: !!options.failOnStatusCode,
|
||||
ignoreHTTPSErrors: !!options.ignoreHTTPSErrors,
|
||||
maxRedirects: options.maxRedirects,
|
||||
httpCredentials: options.httpCredentials,
|
||||
clientCertificates: options.clientCertificates,
|
||||
proxy,
|
||||
|
|
|
@ -17573,6 +17573,13 @@ export interface APIRequest {
|
|||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to `20`. Pass `0` to not follow redirects. This can be overwritten for each request
|
||||
* individually.
|
||||
*/
|
||||
maxRedirects?: number;
|
||||
|
||||
/**
|
||||
* Network proxy settings.
|
||||
*/
|
||||
|
|
|
@ -644,6 +644,7 @@ export type PlaywrightNewRequestParams = {
|
|||
passphrase?: string,
|
||||
pfx?: Binary,
|
||||
}[],
|
||||
maxRedirects?: number,
|
||||
httpCredentials?: {
|
||||
username: string,
|
||||
password: string,
|
||||
|
@ -676,6 +677,7 @@ export type PlaywrightNewRequestOptions = {
|
|||
passphrase?: string,
|
||||
pfx?: Binary,
|
||||
}[],
|
||||
maxRedirects?: number,
|
||||
httpCredentials?: {
|
||||
username: string,
|
||||
password: string,
|
||||
|
|
|
@ -770,6 +770,7 @@ Playwright:
|
|||
key: binary?
|
||||
passphrase: string?
|
||||
pfx: binary?
|
||||
maxRedirects: number?
|
||||
httpCredentials:
|
||||
type: object?
|
||||
properties:
|
||||
|
|
|
@ -437,6 +437,8 @@ it('should return body for failing requests', async ({ playwright, server }) =>
|
|||
await request.dispose();
|
||||
});
|
||||
|
||||
const HTTP_METHODS = ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH'] as const;
|
||||
|
||||
it('should throw an error when maxRedirects is exceeded', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/b/c/redirect3');
|
||||
|
@ -444,7 +446,7 @@ it('should throw an error when maxRedirects is exceeded', async ({ playwright, s
|
|||
server.setRedirect('/b/c/redirect4', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH']) {
|
||||
for (const method of HTTP_METHODS) {
|
||||
for (const maxRedirects of [1, 2, 3])
|
||||
await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method: method, maxRedirects: maxRedirects })).rejects.toThrow('Max redirect count exceeded');
|
||||
}
|
||||
|
@ -456,7 +458,7 @@ it('should not follow redirects when maxRedirects is set to 0', async ({ playwri
|
|||
server.setRedirect('/b/c/redirect2', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH']){
|
||||
for (const method of HTTP_METHODS){
|
||||
const response = await request.fetch(`${server.PREFIX}/a/redirect1`, { method, maxRedirects: 0 });
|
||||
expect(response.headers()['location']).toBe('/b/c/redirect2');
|
||||
expect(response.status()).toBe(302);
|
||||
|
@ -469,11 +471,59 @@ it('should throw an error when maxRedirects is less than 0', async ({ playwright
|
|||
server.setRedirect('/b/c/redirect2', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext();
|
||||
for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH'])
|
||||
for (const method of HTTP_METHODS)
|
||||
await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method, maxRedirects: -1 })).rejects.toThrow(`'maxRedirects' must be greater than or equal to '0'`);
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
it('should not follow redirects when maxRedirects is set to 0 in newContext', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext({ maxRedirects: 0 });
|
||||
for (const method of HTTP_METHODS) {
|
||||
const response = await request.fetch(`${server.PREFIX}/a/redirect1`, { method });
|
||||
expect(response.headers()['location']).toBe('/b/c/redirect2');
|
||||
expect(response.status()).toBe(302);
|
||||
}
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
it('should follow redirects up to maxRedirects limit set in newContext', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/b/c/redirect3');
|
||||
server.setRedirect('/b/c/redirect3', '/b/c/redirect4');
|
||||
server.setRedirect('/b/c/redirect4', '/simple.json');
|
||||
|
||||
for (const maxRedirects of [1, 2, 3, 4]) {
|
||||
const request = await playwright.request.newContext({ maxRedirects });
|
||||
for (const method of HTTP_METHODS) {
|
||||
if (maxRedirects < 4) {
|
||||
await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method }))
|
||||
.rejects.toThrow('Max redirect count exceeded');
|
||||
} else {
|
||||
const response = await request.fetch(`${server.PREFIX}/a/redirect1`, { method });
|
||||
expect(response.status()).toBe(200);
|
||||
}
|
||||
}
|
||||
await request.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
it('should use maxRedirects from fetch when provided, overriding newContext', async ({ playwright, server }) => {
|
||||
server.setRedirect('/a/redirect1', '/b/c/redirect2');
|
||||
server.setRedirect('/b/c/redirect2', '/b/c/redirect3');
|
||||
server.setRedirect('/b/c/redirect3', '/b/c/redirect4');
|
||||
server.setRedirect('/b/c/redirect4', '/simple.json');
|
||||
|
||||
const request = await playwright.request.newContext({ maxRedirects: 1 });
|
||||
for (const method of HTTP_METHODS) {
|
||||
const response = await request.fetch(`${server.PREFIX}/a/redirect1`, { method, maxRedirects: 4 });
|
||||
expect(response.status()).toBe(200);
|
||||
}
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
it('should keep headers capitalization', async ({ playwright, server }) => {
|
||||
const request = await playwright.request.newContext();
|
||||
const [serverRequest, response] = await Promise.all([
|
||||
|
|
Loading…
Reference in New Issue