Skip to content

Commit

Permalink
fix: make all test_intercpet.js tests pass again
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed Nov 28, 2021
1 parent 0756a34 commit 60dbe34
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 29 deletions.
72 changes: 60 additions & 12 deletions lib/intercept.js
Expand Up @@ -303,20 +303,34 @@ function activate() {
)

if (!matches && allowUnmocked) {
globalEmitter.emit('no match', req)
globalEmitter.emit('no match', overriddenRequest)

return request.nockSendRealRequest()
}

debug('using', interceptors.length, 'interceptors')

// TODO: find out when this is needed and make it work again
// interceptors.forEach(interceptor => {
// this.setHostHeaderUsingInterceptor(interceptor)
// We need to override the host header in case the `filteringScope` option is used.
//
// Example:
//
// ```js
// const scope = nock('https://api.dropbox.com', {
// filteringScope: scope => /^https:\/\/api[0-9]*.dropbox.com/.test(scope),
// })

const requestBodyBuffers = []
const requestBodyBuffer = Buffer.concat(requestBodyBuffers)
// .get('/1/metadata/auto/Photos?include_deleted=false&list=true')
// .reply(200)
// ```
//
// In the above example we want to match requests to any subdomain of `dropbox.com` matching `/api[0-9]*/`.
// But in the actual request, it should look as if the request went to `api.dropbox.com` as defined in the scope.
//
// I guess this is for making work better with recording. ~@gr2m
interceptors.forEach(interceptor => {
setHostHeaderUsingInterceptor(options, overriddenRequest, interceptor)
})

const requestBodyBuffer = overriddenRequest.nockGetRequestBodyAsBuffer()
// When request body is a binary buffer we internally use in its hexadecimal
// representation.
const requestBodyIsUtf8Representable =
Expand Down Expand Up @@ -350,7 +364,12 @@ function activate() {
return
}

globalEmitter.emit('no match', req, options, requestBodyString)
globalEmitter.emit(
'no match',
overriddenRequest,
options,
requestBodyString
)

// Try to find a hostname match that allows unmocked.
const allowUnmockedForHostName = interceptors.some(
Expand All @@ -370,15 +389,44 @@ function activate() {

globalEmitter.emit('no match', options)

if (isOn() && isEnabledForNetConnect(options)) {
const error = new NetConnectNotAllowedError(options.host, options.path)
return new ErroringClientRequest(error)
if (isOff() || isEnabledForNetConnect(options)) {
return overriddenRequest.nockSendRealRequest()
}

return request.nockSendRealRequest()
const error = new NetConnectNotAllowedError(options.host, options.path)
return new ErroringClientRequest(error)
})
}

/**
* Set request headers of the given request. This is needed both during the
* routing phase, in case header filters were specified, and during the
* interceptor-playback phase, to correctly pass mocked request headers.
* TODO There are some problems with this; see https://github.com/nock/nock/issues/1718
*/
function setHostHeaderUsingInterceptor(options, request, interceptor) {
// If a filtered scope is being used we have to use scope's host in the
// header, otherwise 'host' header won't match.
// NOTE: We use lower-case header field names throughout Nock.
const HOST_HEADER = 'host'
if (interceptor.__nock_filteredScope && interceptor.__nock_scopeHost) {
options.headers[HOST_HEADER] = interceptor.__nock_scopeHost
request.setHeader(HOST_HEADER, interceptor.__nock_scopeHost)
} else {
// For all other cases, we always add host header equal to the requested
// host unless it was already defined.
if (options.host && !request.getHeader(HOST_HEADER)) {
let hostHeader = options.host

if (options.port === 80 || options.port === 443) {
hostHeader = hostHeader.split(':')[0]
}

request.setHeader(HOST_HEADER, hostHeader)
}
}
}

module.exports = {
addInterceptor,
remove,
Expand Down
2 changes: 1 addition & 1 deletion modules/intercept-node-http/index.js
Expand Up @@ -28,7 +28,7 @@ function setupNodeIntercept(onIntercept) {
createNockInterceptedClientRequest(onIntercept)
http.ClientRequest = NockInterceptedClientRequest

overrideRequests(function (proto, overriddenRequest, args) {
overrideRequests(function (...args) {
return new NockInterceptedClientRequest(...args)
})

Expand Down
17 changes: 15 additions & 2 deletions modules/intercept-node-http/lib/client-request/index.js
Expand Up @@ -67,7 +67,7 @@ function createNockInterceptedClientRequest(onIntercept) {
// override public API methods
this.write = (...args) => handleWrite(this, state, ...args)
this.end = (...args) => handleEnd(this, state, ...args)
this.flushHeaders = () => handleFlushHeaders(state, this)
this.flushHeaders = () => handleFlushHeaders(this, state)

// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect
if (options.headers.expect === '100-continue') {
Expand Down Expand Up @@ -111,6 +111,9 @@ function createNockInterceptedClientRequest(onIntercept) {
state.onResponseCallback
)

// do not call response callback twice
this.removeListener('response', state.onResponseCallback)

propagate(newRequest, this)

// TODO: pass raw buffer of request body as received by mocked request
Expand All @@ -120,6 +123,15 @@ function createNockInterceptedClientRequest(onIntercept) {
// the real requests is sent out, and that it's called when
// the response is mocked
}

/**
* Expose method to retrieve request body as a buffer for matching purposes
*
* @returns {Buffer}
*/
this.nockGetRequestBodyAsBuffer = function nockGetRequestBodyAsBuffer() {
return Buffer.concat(state.requestBodyBuffers)
}
}
}

Expand Down Expand Up @@ -276,10 +288,11 @@ function prepareForIntercept(request, state) {
}

// set host header
let hostHeader = options.host
let hostHeader = options.host || options.hostname
if (options.port === 80 || options.port === 443) {
hostHeader = hostHeader.split(':')[0]
}

request.setHeader('host', hostHeader)

// wait to emit the finish event until we know for sure that the request will be intercepted,
Expand Down
29 changes: 15 additions & 14 deletions modules/intercept-node-http/lib/override-requests.js
@@ -1,6 +1,8 @@
const http = require('http')
const https = require('https')

const normalizeNodeRequestArguments = require('./normalize-request-arguments')

module.exports = overrideRequests

/**
Expand All @@ -17,27 +19,26 @@ module.exports = overrideRequests
function overrideRequests(newRequest) {
;['http', 'https'].forEach(function (moduleName) {
const module = moduleName === 'http' ? http : https
const overriddenRequest = module.request
const overriddenGet = module.get

// https://nodejs.org/api/http.html#http_http_request_url_options_callback
module.request = function (url, options, callback) {
return newRequest(moduleName, overriddenRequest.bind(module), [
url,
options,
callback,
])
module.request = function (...args) {
const { options, callback } = normalizeNodeRequestArguments(...args)
return newRequest(withDefaultProtocol(moduleName, options), callback)
}

// https://nodejs.org/api/http.html#http_http_get_options_callback
module.get = function (url, options, callback) {
const req = newRequest(moduleName, overriddenGet.bind(module), [
url,
options,
callback,
])
module.get = function (...args) {
const { options, callback } = normalizeNodeRequestArguments(...args)
const req = newRequest(withDefaultProtocol(moduleName, options), callback)
req.end()
return req
}
})
}

function withDefaultProtocol(moduleName, options) {
return {
protocol: moduleName + ':',
...options,
}
}

0 comments on commit 60dbe34

Please sign in to comment.