Skip to content

Commit

Permalink
fix: patch and restore Headers in interceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed Jul 7, 2024
1 parent 3e4fcf8 commit 50bdac0
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
10 changes: 1 addition & 9 deletions src/interceptors/ClientRequest/MockHttpSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ import {
RESPONSE_STATUS_CODES_WITHOUT_BODY,
} from '../../utils/responseUtils'
import { createRequestId } from '../../createRequestId'
import {
getRawFetchHeaders,
recordRawFetchHeaders,
} from './utils/recordRawHeaders'
import { getRawFetchHeaders } from './utils/recordRawHeaders'

type HttpConnectionOptions = any

Expand Down Expand Up @@ -125,11 +122,6 @@ export class MockHttpSocket extends MockSocket {
Reflect.set(this, 'getSession', () => undefined)
Reflect.set(this, 'isSessionReused', () => false)
}

// Spy on `Header.prototype.set` and `Header.prototype.append` calls
// and record the raw header names provided. This is to support
// `IncomingMessage.prototype.rawHeaders`.
recordRawFetchHeaders()
}

public emit(event: string | symbol, ...args: any[]): boolean {
Expand Down
11 changes: 11 additions & 0 deletions src/interceptors/ClientRequest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import { toInteractiveRequest } from '../../utils/toInteractiveRequest'
import { normalizeClientRequestArgs } from './utils/normalizeClientRequestArgs'
import { isNodeLikeError } from '../../utils/isNodeLikeError'
import { createServerErrorResponse } from '../../utils/responseUtils'
import {
recordRawFetchHeaders,
restoreHeadersPrototype,
} from './utils/recordRawHeaders'

export class ClientRequestInterceptor extends Interceptor<HttpRequestEventMap> {
static symbol = Symbol('client-request-interceptor')
Expand Down Expand Up @@ -104,12 +108,19 @@ export class ClientRequestInterceptor extends Interceptor<HttpRequestEventMap> {
},
})

// Spy on `Header.prototype.set` and `Header.prototype.append` calls
// and record the raw header names provided. This is to support
// `IncomingMessage.prototype.rawHeaders`.
recordRawFetchHeaders()

this.subscriptions.push(() => {
http.get = originalGet
http.request = originalRequest

https.get = originalHttpsGet
https.request = originalHttpsRequest

restoreHeadersPrototype()
})
}

Expand Down
26 changes: 22 additions & 4 deletions src/interceptors/ClientRequest/utils/recordRawHeaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ type HeaderTuple = [string, string]
type RawHeaders = Array<HeaderTuple>

const kRawHeaders = Symbol('kRawHeaders')
const kHeadersPatched = Symbol('kHeadersPatched')
const kRestoreHeaders = Symbol('kRestoreHeaders')

function recordRawHeader(headers: Headers, args: HeaderTuple) {
if (!Reflect.has(headers, kRawHeaders)) {
Expand Down Expand Up @@ -32,10 +32,22 @@ function recordRawHeader(headers: Headers, args: HeaderTuple) {
* h[Symbol('headers map')] // Map { 'X-Custom' => 'one, two' }
*/
export function recordRawFetchHeaders() {
if (Reflect.get(Headers.prototype.set, kHeadersPatched)) {
return
// Prevent patching the Headers prototype multiple times.
if (Reflect.get(Headers, kRestoreHeaders)) {
return Reflect.get(Headers, kRestoreHeaders)
}

const { set, append, delete: headersDeleteMethod } = Headers.prototype

Object.defineProperty(Headers, kRestoreHeaders, {
value: () => {
Headers.prototype.set = set
Headers.prototype.append = append
Headers.prototype.delete = headersDeleteMethod
},
enumerable: false,
})

Headers.prototype.set = new Proxy(Headers.prototype.set, {
apply(target, thisArg, args: HeaderTuple) {
recordRawHeader(thisArg, args)
Expand Down Expand Up @@ -64,8 +76,14 @@ export function recordRawFetchHeaders() {
return Reflect.apply(target, thisArg, args)
},
})
}

export function restoreHeadersPrototype() {
if (!Reflect.get(Headers, kRestoreHeaders)) {
return
}

Reflect.set(Headers.prototype.set, kHeadersPatched, true)
Reflect.get(Headers, kRestoreHeaders)()
}

export function getRawFetchHeaders(headers: Headers): RawHeaders {
Expand Down

0 comments on commit 50bdac0

Please sign in to comment.