From 81ae790288a8eaae561c2a09e0da167a0ed3d131 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 8 Sep 2021 20:32:52 -0700 Subject: [PATCH] feat(fetch): support ignoreHTTPSErrors (#8795) --- src/server/fetch.ts | 11 ++++++++--- tests/browsercontext-fetch.spec.ts | 11 ++++++++++- tests/browsertype-connect.spec.ts | 2 ++ tests/chromium/chromium.spec.ts | 2 ++ tests/config/utils.ts | 18 ++++++++++++++++++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/server/fetch.ts b/src/server/fetch.ts index 2f9fe465c4..f1b008e56c 100644 --- a/src/server/fetch.ts +++ b/src/server/fetch.ts @@ -54,14 +54,19 @@ export async function playwrightFetch(context: BrowserContext, params: types.Fet const timeout = context._timeoutSettings.timeout(params); const deadline = monotonicTime() + timeout; - const fetchResponse = await sendRequest(context, new URL(params.url, context._options.baseURL), { + const options: https.RequestOptions & { maxRedirects: number, deadline: number } = { method, headers, agent, maxRedirects: 20, timeout, deadline - }, params.postData); + }; + // rejectUnauthorized = undefined is treated as true in node 12. + if (context._options.ignoreHTTPSErrors) + options.rejectUnauthorized = false; + + const fetchResponse = await sendRequest(context, new URL(params.url, context._options.baseURL), options, params.postData); const fetchUid = context.storeFetchResponseBody(fetchResponse.body); return { fetchResponse: { ...fetchResponse, fetchUid } }; } catch (e) { @@ -102,7 +107,7 @@ async function updateRequestCookieHeader(context: BrowserContext, url: URL, opti } } -async function sendRequest(context: BrowserContext, url: URL, options: http.RequestOptions & { maxRedirects: number, deadline: number }, postData?: Buffer): Promise{ +async function sendRequest(context: BrowserContext, url: URL, options: https.RequestOptions & { maxRedirects: number, deadline: number }, postData?: Buffer): Promise{ await updateRequestCookieHeader(context, url, options); return new Promise((fulfill, reject) => { const requestConstructor: ((url: URL, options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void) => http.ClientRequest) diff --git a/tests/browsercontext-fetch.spec.ts b/tests/browsercontext-fetch.spec.ts index 2fc88df5a4..a63a9e6c0a 100644 --- a/tests/browsercontext-fetch.spec.ts +++ b/tests/browsercontext-fetch.spec.ts @@ -19,6 +19,7 @@ import zlib from 'zlib'; import { pipeline } from 'stream'; import { contextTest as it, expect } from './config/browserTest'; import type { Response } from '..'; +import { suppressCertificateWarning } from './config/utils'; it.skip(({ mode }) => mode !== 'default'); @@ -459,6 +460,7 @@ it('should support https', async ({context, httpsServer}) => { const oldValue = process.env['NODE_TLS_REJECT_UNAUTHORIZED']; // https://stackoverflow.com/a/21961005/552185 process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; + suppressCertificateWarning(); try { // @ts-expect-error const response = await context._fetch(httpsServer.EMPTY_PAGE); @@ -468,7 +470,14 @@ it('should support https', async ({context, httpsServer}) => { } }); -it('should resolve url relative to baseURL', async function({browser, server, contextFactory, contextOptions}) { +it('should support ignoreHTTPSErrors', async ({contextFactory, contextOptions, httpsServer}) => { + const context = await contextFactory({ ...contextOptions, ignoreHTTPSErrors: true }); + // @ts-expect-error + const response = await context._fetch(httpsServer.EMPTY_PAGE); + expect(response.status()).toBe(200); +}); + +it('should resolve url relative to baseURL', async function({server, contextFactory, contextOptions}) { const context = await contextFactory({ ...contextOptions, baseURL: server.PREFIX, diff --git a/tests/browsertype-connect.spec.ts b/tests/browsertype-connect.spec.ts index 66b3eebb81..301bf28f14 100644 --- a/tests/browsertype-connect.spec.ts +++ b/tests/browsertype-connect.spec.ts @@ -20,6 +20,7 @@ import fs from 'fs'; import * as path from 'path'; import { getUserAgent } from '../lib/utils/utils'; import WebSocket from 'ws'; +import { suppressCertificateWarning } from './config/utils'; test.slow(true, 'All connect tests are slow'); @@ -30,6 +31,7 @@ test('should connect over wss', async ({browserType , startRemoteServer, httpsSe const oldValue = process.env['NODE_TLS_REJECT_UNAUTHORIZED']; // https://stackoverflow.com/a/21961005/552185 process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; + suppressCertificateWarning(); try { httpsServer.onceWebSocketConnection((ws, request) => { const remote = new WebSocket(remoteServer.wsEndpoint(), [], { diff --git a/tests/chromium/chromium.spec.ts b/tests/chromium/chromium.spec.ts index 351b07071a..f7b61149ed 100644 --- a/tests/chromium/chromium.spec.ts +++ b/tests/chromium/chromium.spec.ts @@ -19,6 +19,7 @@ import { contextTest as test, expect } from '../config/browserTest'; import { playwrightTest } from '../config/browserTest'; import http from 'http'; import { getUserAgent } from '../../lib/utils/utils'; +import { suppressCertificateWarning } from '../config/utils'; test('should create a worker from a service worker', async ({page, server}) => { const [worker] = await Promise.all([ @@ -307,6 +308,7 @@ playwrightTest('should connect via https', async ({ browserType, browserOptions, const oldValue = process.env['NODE_TLS_REJECT_UNAUTHORIZED']; // https://stackoverflow.com/a/21961005/552185 process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; + suppressCertificateWarning(); try { const cdpBrowser = await browserType.connectOverCDP(`https://localhost:${httpsServer.PORT}/`); const contexts = cdpBrowser.contexts(); diff --git a/tests/config/utils.ts b/tests/config/utils.ts index ba0d776964..89d0315895 100644 --- a/tests/config/utils.ts +++ b/tests/config/utils.ts @@ -69,4 +69,22 @@ export function chromiumVersionLessThan(a: string, b: string) { return true; } return false; +} + +let didSuppressUnverifiedCertificateWarning = false; +let originalEmitWarning: (warning: string | Error, ...args: any[]) => void; +export function suppressCertificateWarning() { + if (didSuppressUnverifiedCertificateWarning) + return; + didSuppressUnverifiedCertificateWarning = true; + // Supress one-time warning: + // https://github.com/nodejs/node/blob/1bbe66f432591aea83555d27dd76c55fea040a0d/lib/internal/options.js#L37-L49 + originalEmitWarning = process.emitWarning; + process.emitWarning = (warning, ...args) => { + if (typeof warning === 'string' && warning.includes('NODE_TLS_REJECT_UNAUTHORIZED')) { + process.emitWarning = originalEmitWarning; + return; + } + return originalEmitWarning.call(process, warning, ...args); + }; } \ No newline at end of file