diff --git a/src/interceptors/ClientRequest/ClientRequestOverride.ts b/src/interceptors/ClientRequest/ClientRequestOverride.ts index d8a4443ff..d8ef2db83 100644 --- a/src/interceptors/ClientRequest/ClientRequestOverride.ts +++ b/src/interceptors/ClientRequest/ClientRequestOverride.ts @@ -17,6 +17,7 @@ import { normalizeHttpRequestEndParams } from './utils/normalizeHttpRequestEndPa const createDebug = require('debug') export function createClientRequestOverrideClass( + protocol: string, middleware: RequestMiddleware, performOriginalRequest: typeof http.request, originalClientRequest: typeof http.ClientRequest @@ -25,7 +26,7 @@ export function createClientRequestOverrideClass( this: http.ClientRequest, ...args: Parameters ) { - const [url, options, callback] = normalizeHttpRequestParams(...args) + const [url, options, callback] = normalizeHttpRequestParams(protocol, ...args) const usesHttps = url.protocol === 'https:' let requestBodyBuffer: Buffer[] = [] diff --git a/src/interceptors/ClientRequest/index.ts b/src/interceptors/ClientRequest/index.ts index 947ed78ce..d2b5df838 100644 --- a/src/interceptors/ClientRequest/index.ts +++ b/src/interceptors/ClientRequest/index.ts @@ -31,6 +31,7 @@ function handleRequest( } const ClientRequestOverride = createClientRequestOverrideClass( + protocol, middleware, originalMethod, originalClientRequest diff --git a/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.test.ts b/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.test.ts index 3e0855700..fec453feb 100644 --- a/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.test.ts +++ b/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.test.ts @@ -7,7 +7,7 @@ test('handles [string, callback] input', () => { url, options, callback, - ] = normalizeHttpRequestParams('https://mswjs.io/resource', function cb() {}) + ] = normalizeHttpRequestParams('http', 'https://mswjs.io/resource', function cb() {}) // URL string must be converted to a URL instance expect(url.toJSON()).toEqual(new URL('https://mswjs.io/resource').toJSON()) @@ -33,6 +33,7 @@ test('handles [string, RequestOptions, callback] input', () => { options, callback, ] = normalizeHttpRequestParams( + 'http', 'https://mswjs.io/resource', initialOptions, function cb() {} @@ -50,6 +51,7 @@ test('handles [string, RequestOptions, callback] input', () => { test('handles [URL, callback] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', new URL('https://mswjs.io/resource'), function cb() {} ) @@ -69,6 +71,7 @@ test('handles [URL, callback] input', () => { test('handles [Absolute Legacy URL, callback] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', parse('https://cherry:durian@mswjs.io:12345/resource?apple=banana'), function cb() {} ) @@ -90,6 +93,7 @@ test('handles [Absolute Legacy URL, callback] input', () => { test('handles [Relative Legacy URL, RequestOptions without path set, callback] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', parse('/resource?apple=banana'), {host: 'mswjs.io'}, function cb() {} @@ -109,6 +113,7 @@ test('handles [Relative Legacy URL, RequestOptions without path set, callback] i test('handles [Relative Legacy URL, RequestOptions with path set, callback] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', parse('/resource?apple=banana'), {host: 'mswjs.io', path: '/other?cherry=durian'}, function cb() {} @@ -128,12 +133,13 @@ test('handles [Relative Legacy URL, RequestOptions with path set, callback] inpu test('handles [Relative Legacy URL, callback] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', parse('/resource?apple=banana'), function cb() {} ) // Correct WHATWG URL generated - expect(url.toJSON()).toMatch(getUrlByRequestOptions({path: '/resource?apple=banana'}).toJSON()) + expect(url.toJSON()).toMatch(getUrlByRequestOptions('http', {path: '/resource?apple=banana'}).toJSON()) // Check path is in options expect(options).toHaveProperty('protocol', 'http:') @@ -145,11 +151,12 @@ test('handles [Relative Legacy URL, callback] input', () => { test('handles [Relative Legacy URL] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', parse('/resource?apple=banana') ) // Correct WHATWG URL generated - expect(url.toJSON()).toMatch(getUrlByRequestOptions({path: '/resource?apple=banana'}).toJSON()) + expect(url.toJSON()).toMatch(getUrlByRequestOptions('http', {path: '/resource?apple=banana'}).toJSON()) // Check path is in options expect(options).toHaveProperty('protocol', 'http:') @@ -161,6 +168,7 @@ test('handles [Relative Legacy URL] input', () => { test('handles [URL, RequestOptions, callback] input', () => { const [url, options, callback] = normalizeHttpRequestParams( + 'http', new URL('https://mswjs.io/resource'), { headers: { @@ -196,6 +204,7 @@ test('handles [RequestOptions, callback] input', () => { }, } const [url, options, callback] = normalizeHttpRequestParams( + 'http', initialOptions, function cb() {} ) @@ -212,6 +221,7 @@ test('handles [RequestOptions, callback] input', () => { test('handles [Empty RequestOptions, callback] input', () => { const [_, __, callback] = normalizeHttpRequestParams( + 'http', {}, function cb() {} ) @@ -237,6 +247,7 @@ test('handles [PartialRequestOptions, callback] input', () => { agent: false, } const [url, options, callback] = normalizeHttpRequestParams( + 'http', initialOptions, function cb() {} ) diff --git a/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.ts b/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.ts index 2a5cdaf73..5c428a96e 100644 --- a/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.ts +++ b/src/interceptors/ClientRequest/utils/normalizeHttpRequestParams.ts @@ -36,6 +36,7 @@ function resolveCallback( * so it always has a `URL` and `RequestOptions`. */ export function normalizeHttpRequestParams( + defaultProtocol: string, ...args: HttpRequestArgs ): [URL, RequestOptions & RequestSelf, HttpRequestCallback?] { let url: URL @@ -83,10 +84,12 @@ export function normalizeHttpRequestParams( return isObject(args[1]) ? normalizeHttpRequestParams( + defaultProtocol, { path: legacyUrl.path, ...args[1] }, args[2] ) : normalizeHttpRequestParams( + defaultProtocol, { path: legacyUrl.path }, args[1] as HttpRequestCallback ) @@ -98,10 +101,10 @@ export function normalizeHttpRequestParams( const resolvedUrl = new URL(legacyUrl.href) return args[1] === undefined - ? normalizeHttpRequestParams(resolvedUrl) + ? normalizeHttpRequestParams(defaultProtocol, resolvedUrl) : typeof args[1] === 'function' - ? normalizeHttpRequestParams(resolvedUrl, args[1]) - : normalizeHttpRequestParams(resolvedUrl, args[1], args[2]) + ? normalizeHttpRequestParams(defaultProtocol, resolvedUrl, args[1]) + : normalizeHttpRequestParams(defaultProtocol, resolvedUrl, args[1], args[2]) } // Handle a given RequestOptions object as-is // and derive the URL instance from it. @@ -109,7 +112,7 @@ export function normalizeHttpRequestParams( options = args[0] debug('given request options:', options) - url = getUrlByRequestOptions(options) + url = getUrlByRequestOptions(defaultProtocol, options) debug('created a URL:', url) callback = resolveCallback(args) diff --git a/src/utils/getUrlByRequestOptions.test.ts b/src/utils/getUrlByRequestOptions.test.ts index 9c22a313b..c94baff54 100644 --- a/src/utils/getUrlByRequestOptions.test.ts +++ b/src/utils/getUrlByRequestOptions.test.ts @@ -8,7 +8,7 @@ test('returns a URL based on the basic RequestOptions', () => { host: '127.0.0.1', path: '/resource', } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('port', '') @@ -21,7 +21,7 @@ test('inherits protocol and port from http.Agent, if set', () => { path: '/', agent: new HttpAgent(), } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('protocol', 'http:') @@ -37,7 +37,7 @@ test('inherits protocol and port from https.Agent, if set', () => { port: 3080, }), } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('protocol', 'https:') @@ -45,12 +45,19 @@ test('inherits protocol and port from https.Agent, if set', () => { expect(url).toHaveProperty('href', 'https://127.0.0.1:3080/') }) -test('resolves protocol to "http" given no explicit protocol and no certificate', () => { +test('resolves protocol from default given no explicit protocol and no certificate', () => { const options: RequestOptions = { host: '127.0.0.1', path: '/', } - const url = getUrlByRequestOptions(options) + let url = getUrlByRequestOptions('https', options) + + expect(url).toBeInstanceOf(URL) + expect(url).toHaveProperty('protocol', 'https:') + expect(url).toHaveProperty('port', '') + expect(url).toHaveProperty('href', 'https://127.0.0.1/') + + url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('protocol', 'http:') @@ -64,7 +71,7 @@ test('resolves protocol to "https" given no explicit protocol, but certificate', path: '/secure', cert: '', } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('protocol', 'https:') @@ -78,7 +85,7 @@ test('resolves protocol to "https" given no explicit protocol, but port is 443', port: 443, path: '/resource', } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('port', '') @@ -93,7 +100,7 @@ test('resolves protocol to "https" given no explicit protocol, but agent port is }), path: '/resource', } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('port', '') @@ -107,7 +114,7 @@ test('inherits "port" if given', () => { port: 4002, path: '/', } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('port', '4002') @@ -122,7 +129,7 @@ test('inherits "username" and "password"', () => { path: '/user', auth: 'admin:abc-123', } - const url = getUrlByRequestOptions(options) + const url = getUrlByRequestOptions('http', options) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('username', 'admin') @@ -132,7 +139,7 @@ test('inherits "username" and "password"', () => { }) test('resolves hostname to localhost if none provided', () => { - const url = getUrlByRequestOptions({}) + const url = getUrlByRequestOptions('http', {}) expect(url).toBeInstanceOf(URL) expect(url).toHaveProperty('protocol', 'http:') diff --git a/src/utils/getUrlByRequestOptions.ts b/src/utils/getUrlByRequestOptions.ts index 238c4f6a1..374330bf2 100644 --- a/src/utils/getUrlByRequestOptions.ts +++ b/src/utils/getUrlByRequestOptions.ts @@ -7,9 +7,7 @@ const debug = require('debug')('utils getUrlByRequestOptions') type IsomorphicRequestOptions = RequestOptions & RequestSelf export const DEFAULT_PATH = '/' -const DEFAULT_PROTOCOL = 'http:' const DEFAULT_HOST = 'localhost' -const DEFAULT_PORT = 80 const SSL_PORT = 443 function getAgent( @@ -19,6 +17,7 @@ function getAgent( } function getProtocolByRequestOptions( + defaultProtocol: string, options: IsomorphicRequestOptions ): string { if (options.protocol) { @@ -36,7 +35,7 @@ function getProtocolByRequestOptions( const isSecureRequest = options.cert || port === SSL_PORT - return isSecureRequest ? 'https:' : options.uri?.protocol || DEFAULT_PROTOCOL + return isSecureRequest ? 'https:' : options.uri?.protocol || `${defaultProtocol}:` } function getPortByRequestOptions( @@ -49,7 +48,7 @@ function getPortByRequestOptions( const optionsPort = options.port if (optionsPort || agentPort) { - const explicitPort = optionsPort || agentPort || DEFAULT_PORT + const explicitPort = optionsPort || agentPort return Number(explicitPort) } } @@ -68,10 +67,10 @@ function getAuthByRequestOptions(options: IsomorphicRequestOptions) { /** * Creates a `URL` instance from a given `RequestOptions` object. */ -export function getUrlByRequestOptions(options: IsomorphicRequestOptions): URL { +export function getUrlByRequestOptions(defaultProtocol: string, options: IsomorphicRequestOptions): URL { debug('request options', options) - const protocol = getProtocolByRequestOptions(options) + const protocol = getProtocolByRequestOptions(defaultProtocol, options) const host = getHostByRequestOptions(options) const port = getPortByRequestOptions(options) const path = options.path || DEFAULT_PATH