diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index f673523705..d666b4417c 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -6,6 +6,7 @@ _Released 7/15/2025 (PENDING)_ **Bugfixes:** - Fixed a regression introduced in [`14.5.0`](https://docs.cypress.io/guides/references/changelog#14-5-0) where the Stop button would not immediately stop the spec timer. Addresses [#31920](https://github.com/cypress-io/cypress/issues/31920). +- Fixed an issue with the `CloudRequest` where it used the wrong port for `https` requests. Addressed in [#31992](https://github.com/cypress-io/cypress/pull/31992). ## 14.5.1 diff --git a/packages/network/lib/agent.ts b/packages/network/lib/agent.ts index 4848a0a344..978a4b980e 100644 --- a/packages/network/lib/agent.ts +++ b/packages/network/lib/agent.ts @@ -126,7 +126,7 @@ export const createProxySock = (opts: CreateProxySockOpts, cb: CreateProxySockCb export const isRequestHttps = (options: http.RequestOptions) => { // WSS connections will not have an href, but you can tell protocol from the defaultAgent - return _.get(options, '_defaultAgent.protocol') === 'https:' || (options.href || '').slice(0, 6) === 'https:' + return _.get(options, '_defaultAgent.protocol') === 'https:' || options.protocol === 'https:' || (options.href || '').slice(0, 6) === 'https:' } export const isResponseStatusCode200 = (head: string) => { @@ -226,6 +226,11 @@ export class CombinedAgent { const isHttps = isRequestHttps(options) + // Ensure that HTTPS requests are using 443 + if (isHttps && options.port === 80) { + options.port = 443 + } + if (!options.href) { // options.path can contain query parameters, which url.format will not-so-kindly urlencode for us... // so just append it to the resultant URL string diff --git a/packages/server/test/unit/cloud/api/cloud_request_spec.ts b/packages/server/test/unit/cloud/api/cloud_request_spec.ts index 7f3f6db6ee..999db03af7 100644 --- a/packages/server/test/unit/cloud/api/cloud_request_spec.ts +++ b/packages/server/test/unit/cloud/api/cloud_request_spec.ts @@ -6,7 +6,7 @@ import agent from '@packages/network/lib/agent' import axios, { CreateAxiosDefaults, AxiosInstance } from 'axios' import debugLib from 'debug' import stripAnsi from 'strip-ansi' -import { createCloudRequest } from '../../../../lib/cloud/api/cloud_request' +import { CloudRequest, createCloudRequest } from '../../../../lib/cloud/api/cloud_request' import cloudApi from '../../../../lib/cloud/api' import app_config from '../../../../config/app.json' import os from 'os' @@ -14,6 +14,9 @@ import pkg from '@packages/root' import { transformError } from '../../../../lib/cloud/api/axios_middleware/transform_error' import { DestroyableProxy, fakeServer, fakeProxy } from './utils/fake_proxy_server' import dedent from 'dedent' +import { PassThrough } from 'stream' +import fetch from 'cross-fetch' +import nock from 'nock' chai.use(sinonChai) @@ -444,6 +447,48 @@ describe('CloudRequest', () => { }) }) + describe('https requests', () => { + it('handles https requests properly', async () => { + nock.restore() + + // @ts-ignore + const addRequestSpy = sinon.stub(agent.httpsAgent, 'addRequest').callsFake((req, options) => { + // fake IncomingMessage + const res = new PassThrough() as any + + res.statusCode = 200 + res.headers = { + 'content-type': 'application/json', + } + + process.nextTick(() => { + req.emit('response', res) + res.write(JSON.stringify({ ok: options.port === 443 && options.protocol === 'https:' })) + res.end() + }) + }) + + const result1 = await CloudRequest.post('https://cloud.cypress.io/ping', {}) + + expect(result1.data).to.eql({ ok: true }) + + const result2 = await createCloudRequest({ baseURL: 'https://api.cypress.io' }).post('/ping', {}) + + expect(result2.data).to.eql({ ok: true }) + + const result3 = await fetch('https://cloud.cypress.io/ping', { + method: 'POST', + body: '{}', + // @ts-expect-error - this is supported + agent, + }) + + expect(await result3.json()).to.eql({ ok: true }) + + expect(addRequestSpy).to.have.been.calledThrice + }) + }) + ;[undefined, 'development', 'test', 'staging', 'production'].forEach((env) => { describe(`base url for CYPRESS_CONFIG_ENV "${env}"`, () => { let prevEnv