hyperswitch
Advanced tools
Comparing version 0.1.2 to 0.1.3
@@ -103,21 +103,66 @@ "use strict"; | ||
function logResponse(opts, response) { | ||
var logLevel = 'trace/request'; | ||
if (response.status >= 500) { | ||
logLevel = 'error/request'; | ||
} else if (response.status >= 400) { | ||
logLevel = 'info/request'; | ||
} | ||
opts.log(logLevel, { | ||
message: response.message, | ||
res: response, | ||
stack: response.stack | ||
}); | ||
} | ||
/** | ||
* Removes Hop-To-Hop headers that might be | ||
* proxied from a backend service | ||
* | ||
* @param {Object} rh response headers | ||
* @private | ||
*/ | ||
function removeHopToHopHeaders(rh) { | ||
[ | ||
'connection', | ||
'keep-alive', | ||
'public', | ||
'proxy-authenticate', | ||
'transfer-encoding', | ||
'content-length', | ||
'content-encoding' | ||
].forEach(function(headerName) { | ||
// Need to delete properties and not set to undefined | ||
// because node passes 'undefined' to client. | ||
if (rh[headerName]) { | ||
delete rh[headerName]; | ||
} | ||
}); | ||
} | ||
/** | ||
* Set up basic CORS in response headers | ||
* | ||
* @param {Object} rh Response headers object | ||
* @private | ||
*/ | ||
function setCORSHeaders(rh) { | ||
rh['access-control-allow-origin'] = '*'; | ||
rh['access-control-allow-methods'] = 'GET'; | ||
rh['access-control-allow-headers'] = 'accept, content-type'; | ||
rh['access-control-expose-headers'] = 'etag'; | ||
} | ||
function handleResponse(opts, req, resp, response) { | ||
if (response && response.status) { | ||
if (!response.headers) { | ||
response.headers = {}; | ||
} | ||
var rh = response.headers = response.headers || {}; | ||
var rh = response.headers; | ||
removeHopToHopHeaders(rh); | ||
setCORSHeaders(rh); | ||
// Default to no server-side caching | ||
if (!rh['cache-control']) { | ||
rh['cache-control'] = 'private, max-age=0, s-maxage=0, must-revalidate'; | ||
} | ||
rh['cache-control'] = rh['cache-control'] | ||
|| 'private, max-age=0, s-maxage=0, must-revalidate'; | ||
// Set up CORS | ||
rh['access-control-allow-origin'] = '*'; | ||
rh['access-control-allow-methods'] = 'GET'; | ||
rh['access-control-allow-headers'] = 'accept, content-type'; | ||
rh['access-control-expose-headers'] = 'etag'; | ||
// Set up security headers | ||
@@ -133,13 +178,3 @@ // https://www.owasp.org/index.php/List_of_useful_HTTP_headers | ||
var logLevel = 'trace/request'; | ||
if (response.status >= 500) { | ||
logLevel = 'error/request'; | ||
} else if (response.status >= 400) { | ||
logLevel = 'info/request'; | ||
} | ||
opts.log(logLevel, { | ||
message: response.message, | ||
res: response, | ||
stack: response.stack | ||
}); | ||
logResponse(opts, response); | ||
@@ -162,20 +197,14 @@ var body; | ||
if (!response.headers['content-type']) { | ||
response.headers['content-type'] = 'application/problem+json'; | ||
} | ||
rh['content-type'] = rh['content-type'] | ||
|| 'application/problem+json'; | ||
if (response.status === 404) { | ||
if (!body.type) { body.type = 'not_found'; } | ||
if (!body.title) { body.title = 'Not found.'; } | ||
body.type = body.type || 'not_found'; | ||
body.title = body.title || 'Not found.'; | ||
} | ||
if (response.status >= 400) { | ||
if (!body.uri) { body.uri = req.uri; } | ||
if (!body.method) { body.method = req.method; } | ||
} | ||
body.uri = body.uri || req.uri; | ||
body.method = body.method || req.method; | ||
body.type = body.type || 'unknown_error'; | ||
if (!body.type) { | ||
body.type = 'unknown_error'; | ||
} | ||
// Prefix error base URL | ||
@@ -188,3 +217,2 @@ // TODO: make the prefix configurable | ||
if (req.method === 'head') { | ||
delete response.headers['content-length']; | ||
delete response.body; | ||
@@ -204,5 +232,3 @@ } | ||
if (typeof body === 'object') { | ||
if (!response.headers['content-type']) { | ||
response.headers['content-type'] = 'application/json'; | ||
} | ||
rh['content-type'] = rh['content-type'] || 'application/json'; | ||
body = new Buffer(JSON.stringify(body)); | ||
@@ -213,10 +239,8 @@ } else { | ||
} | ||
var cType = response.headers['content-type']; | ||
var cType = rh['content-type']; | ||
if (/\bgzip\b/.test(req.headers['accept-encoding']) | ||
&& /^application\/json\b|^text\//.test(cType)) { | ||
if (response.headers['content-length']) { | ||
delete response.headers['content-length']; | ||
} | ||
response.headers['content-encoding'] = 'gzip'; | ||
resp.writeHead(response.status, '', response.headers); | ||
rh['content-encoding'] = 'gzip'; | ||
resp.writeHead(response.status, '', rh); | ||
var zStream = zlib.createGzip({ level: 3 }); | ||
@@ -230,18 +254,11 @@ zStream.pipe(resp); | ||
} else if (bodyIsStream) { | ||
resp.writeHead(response.status, '', response.headers); | ||
resp.writeHead(response.status, '', rh); | ||
body.pipe(resp); | ||
} else { | ||
response.headers['content-length'] = body.length; | ||
resp.writeHead(response.status, '', response.headers); | ||
rh['content-length'] = body.length; | ||
resp.writeHead(response.status, '', rh); | ||
resp.end(body); | ||
} | ||
} else { | ||
if (response.headers['content-length']) { | ||
opts.log('warn/response/content-length', { | ||
res: response, | ||
reason: new Error('Invalid content-length') | ||
}); | ||
delete response.headers['content-length']; | ||
} | ||
resp.writeHead(response.status, '', response.headers); | ||
resp.writeHead(response.status, '', rh); | ||
resp.end(); | ||
@@ -255,6 +272,6 @@ } | ||
if (!response) { response = {}; } | ||
if (!response.headers) { response.headers = {}; } | ||
response = response || {}; | ||
response.headers = response.headers || {}; | ||
response.headers['content-type'] = 'application/problem+json'; | ||
response.headers['content-type'] = 'application/problem+json'; | ||
resp.writeHead(response.status || 500, '', response.headers); | ||
@@ -452,2 +469,2 @@ resp.end(req.method === 'head' ? undefined : JSON.stringify({ | ||
module.exports = main; | ||
} | ||
} |
{ | ||
"name": "hyperswitch", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "REST API creation framework", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -106,3 +106,15 @@ 'use strict'; | ||
it('Should strip out hop-to-hop headers', function() { | ||
return preq.get({ | ||
uri: server.hostPort + '/service/hop_to_hop' | ||
}) | ||
.then(function(res) { | ||
assert.deepEqual(res.status, 200); | ||
assert.deepEqual(res.headers.hasOwnProperty('transfer-encoding'), false); | ||
assert.deepEqual(res.headers.hasOwnProperty('public'), false); | ||
assert.deepEqual(res.headers.hasOwnProperty('content-encoding'), false); | ||
}); | ||
}); | ||
after(function() { return server.stop(); }); | ||
}); |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
148752
39
3404
5