Skip to content

Commit

Permalink
feat(overrider): added support for header modifications before end()
Browse files Browse the repository at this point in the history
* fix: added support for testing header modification with http-proxy
* Remove pointless options.headers checks
  • Loading branch information
AlexGilleran authored and mastermatt committed Jul 22, 2019
1 parent 213014b commit 4a4b8ec
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 10 deletions.
5 changes: 0 additions & 5 deletions lib/interceptor.js
Expand Up @@ -193,11 +193,6 @@ Interceptor.prototype.reqheaderMatches = function reqheaderMatches(
options,
key
) {
// We don't try to match request headers if these weren't even specified in the request.
if (!options.headers) {
return true
}

const reqHeader = this.reqheaders[key]
let header = options.headers[key]
if (header && typeof header !== 'string' && header.toString) {
Expand Down
8 changes: 5 additions & 3 deletions lib/request_overrider.js
Expand Up @@ -39,9 +39,7 @@ function setRequestHeaders(req, options, interceptor) {
// NOTE: We use lower-case header field names throughout Nock.
const HOST_HEADER = 'host'
if (interceptor.__nock_filteredScope && interceptor.__nock_scopeHost) {
if (options && options.headers) {
options.headers[HOST_HEADER] = interceptor.__nock_scopeHost
}
options.headers[HOST_HEADER] = interceptor.__nock_scopeHost
setHeader(req, HOST_HEADER, interceptor.__nock_scopeHost)
} else {
// For all other cases, we always add host header equal to the
Expand Down Expand Up @@ -233,6 +231,10 @@ function RequestOverrider(req, options, interceptors, remove) {
/// like to change request.path in mid-flight.
options.path = req.path

// similarly, node-http-proxy will modify headers in flight, so we have to put the headers back
// into options
options.headers = req.getHeaders()

// fixes #976
options.protocol = `${options.proto}:`

Expand Down
91 changes: 89 additions & 2 deletions tests/test_intercept.js
Expand Up @@ -440,7 +440,11 @@ test('emits error if https route is missing', t => {
t.equal(
err.message.trim(),
`Nock: No match for request ${JSON.stringify(
{ method: 'GET', url: 'https://example.test/abcdef892932' },
{
method: 'GET',
url: 'https://example.test/abcdef892932',
headers: {},
},
null,
2
)}`
Expand Down Expand Up @@ -474,7 +478,11 @@ test('emits error if https route is missing', t => {
t.equal(
err.message.trim(),
`Nock: No match for request ${JSON.stringify(
{ method: 'GET', url: 'https://example.test:123/dsadsads' },
{
method: 'GET',
url: 'https://example.test:123/dsadsads',
headers: {},
},
null,
2
)}`
Expand Down Expand Up @@ -1340,3 +1348,82 @@ test('three argument form of http.request: URL, options, and callback', t => {
})
})
})

/*
* This test imitates a feature of node-http-proxy (https://github.com/nodejitsu/node-http-proxy) -
* modifying headers for an in-flight request by modifying them.
*/
test('works when headers are removed on the socket event', t => {
// Set up a nock that will fail if it gets an "authorization" header.
const serviceScope = nock('http://service', {
badheaders: ['authorization'],
})
.get('/endpoint')
.reply(200)

// Create a server to act as our reverse proxy.
const server = http.createServer((request, response) => {
// Make a request to the nock instance with the same request that came in.
const proxyReq = http.request({
host: 'service',
// Get the path from the incoming request and pass it through
path: `/${request.url
.split('/')
.slice(1)
.join('/')}`,
headers: request.headers,
})

// When we connect, remove the authorization header (node-http-proxy uses this event to do it)
proxyReq.on('socket', function() {
proxyReq.removeHeader('authorization')

// End the request here, otherwise it ends up matching the request before socket gets called
// because socket runs on process.nextTick
proxyReq.end()
})

proxyReq.on('response', proxyRes => {
proxyRes.pipe(response)
})

proxyReq.on('error', error => {
console.error(error)
t.error(error)
t.end()
})
})

server
.listen(() => {
// Now that the server's started up, make a request to it with an authorization header.
const req = http.request(
{
hostname: 'localhost',
path: '/endpoint',
port: server.address().port,
method: 'GET',
headers: {
authorization: 'blah',
},
},
res => {
// If we get a request, all good :)
t.equal(200, res.statusCode)
serviceScope.done()
server.close(t.end)
}
)

req.on('error', error => {
t.error(error)
t.end()
})

req.end()
})
.on('error', error => {
t.error(error)
t.end()
})
})

0 comments on commit 4a4b8ec

Please sign in to comment.