Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added compatibility with node-http-proxy header altering #1484

Merged
merged 9 commits into from
Jul 22, 2019
5 changes: 0 additions & 5 deletions lib/interceptor.js
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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()
})
})