diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 0c07abd2a7b2..90b37d301a9d 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -11,6 +11,7 @@ _Released 5/7/2024 (PENDING)_ - Fixed a bug where promises rejected with `undefined` were failing inside `cy.origin()`. Addresses [#23937](https://github.com/cypress-io/cypress/issues/23937). - We now pass the same default Chromium flags to Electron as we do to Chrome. As a result of this change, the application under test's `navigator.webdriver` property will now correctly be `true` when testing in Electron. Fixes [#27939](https://github.com/cypress-io/cypress/issues/27939). +- Fixed network issues in requests using fetch for users where Cypress is run behind a proxy that performs HTTPS decryption (common among corporate proxies). Fixes [#29171](https://github.com/cypress-io/cypress/issues/29171) - Fixed an issue where extra windows weren't being closed between specs in Firefox causing potential issues in subsequent specs. Fixes [#29473](https://github.com/cypress-io/cypress/issues/29473). **Misc:** diff --git a/packages/network/test/support/servers.ts b/packages/network/test/support/servers.ts index b93291424c1c..157685ceda42 100644 --- a/packages/network/test/support/servers.ts +++ b/packages/network/test/support/servers.ts @@ -12,14 +12,18 @@ export interface AsyncServer { listenAsync: (port) => Promise } -function createExpressApp () { +function createExpressApp (requestCallback: (req) => void) { const app: express.Application = express() app.get('/get', (req, res) => { + if (requestCallback) requestCallback(req) + res.send('It worked!') }) app.get('/empty-response', (req, res) => { + if (requestCallback) requestCallback(req) + // ERR_EMPTY_RESPONSE in Chrome setTimeout(() => res.connection.destroy(), 100) }) @@ -45,10 +49,11 @@ export class Servers { wsServer: any wssServer: any caCertificatePath: string + lastRequestHeaders: any start (httpPort: number, httpsPort: number) { return Promise.join( - createExpressApp(), + createExpressApp((req) => this.lastRequestHeaders = req.headers), getCAInformation(), ) .spread((app: Express.Application, [serverCertificateKeys, caCertificatePath]: [serverCertificateKeys: string[], caCertificatePath: string]) => { diff --git a/packages/network/test/unit/agent_spec.ts b/packages/network/test/unit/agent_spec.ts index 38f4942be989..2f39e67cc65d 100644 --- a/packages/network/test/unit/agent_spec.ts +++ b/packages/network/test/unit/agent_spec.ts @@ -227,6 +227,15 @@ describe('lib/agent', function () { }) }) + it('HTTP pages are requested with correct host header when loaded via fetch', function () { + return this.fetch(`http://localhost:${HTTP_PORT}/get`) + .then(() => { + expect(this.servers.lastRequestHeaders).to.include({ + host: `localhost:${HTTP_PORT}`, + }) + }) + }) + it('HTTPS pages can be loaded', function () { return this.request({ url: `https://localhost:${HTTPS_PORT}/get`, @@ -255,6 +264,15 @@ describe('lib/agent', function () { }) }) + it('HTTPS pages are requested with correct host header when loaded via fetch', function () { + return this.fetch(`https://localhost:${HTTPS_PORT}/get`) + .then(() => { + expect(this.servers.lastRequestHeaders).to.include({ + host: 'localhost', + }) + }) + }) + it('HTTPS pages can be loaded via fetch with no explicit port', function () { return this.fetch(`https://localhost/get`) .then((response) => response.text()) @@ -269,6 +287,15 @@ describe('lib/agent', function () { }) }) + it('HTTPS pages requested with correct host header when loaded via fetch with no explicit port', function () { + return this.fetch(`https://localhost/get`) + .then(() => { + expect(this.servers.lastRequestHeaders).to.include({ + host: 'localhost', + }) + }) + }) + it('HTTP errors are catchable', function () { return this.request({ url: `http://localhost:${HTTP_PORT}/empty-response`, diff --git a/patches/node-fetch+2.7.0.patch b/patches/node-fetch+2.7.0.patch new file mode 100644 index 000000000000..f6177233db1a --- /dev/null +++ b/patches/node-fetch+2.7.0.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/node-fetch/lib/index.js b/node_modules/node-fetch/lib/index.js +index 567ff5d..c7e2bd9 100644 +--- a/node_modules/node-fetch/lib/index.js ++++ b/node_modules/node-fetch/lib/index.js +@@ -1449,7 +1449,9 @@ function fetch(url, opts) { + const request = new Request(url, opts); + const options = getNodeRequestOptions(request); + +- const send = (options.protocol === 'https:' ? https : http).request; ++ const isHttps = options.protocol === 'https:'; ++ options.defaultPort = (isHttps ? 443 : 80); ++ const send = (isHttps ? https : http).request; + const signal = request.signal; + + let response = null;