summaryrefslogtreecommitdiff
path: root/lib/_http_incoming.js
diff options
context:
space:
mode:
authorBrian White <mscdex@mscdex.net>2016-12-31 16:24:54 -0500
committerBrian White <mscdex@mscdex.net>2017-01-11 12:54:41 -0500
commit73d94457827f6c2dbef734f40efe5e7812a45f42 (patch)
tree4a3ace6b68713d860b8646d31aa3b002852af7b9 /lib/_http_incoming.js
parentc77ed327d945ad3c09bca55e83213624f98d3825 (diff)
downloadandroid-node-v8-73d94457827f6c2dbef734f40efe5e7812a45f42.tar.gz
android-node-v8-73d94457827f6c2dbef734f40efe5e7812a45f42.tar.bz2
android-node-v8-73d94457827f6c2dbef734f40efe5e7812a45f42.zip
http: try to avoid lowercasing incoming headers
PR-URL: https://github.com/nodejs/node/pull/10558 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
Diffstat (limited to 'lib/_http_incoming.js')
-rw-r--r--lib/_http_incoming.js206
1 files changed, 161 insertions, 45 deletions
diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js
index d02f19424c..53419323f4 100644
--- a/lib/_http_incoming.js
+++ b/lib/_http_incoming.js
@@ -119,6 +119,146 @@ function _addHeaderLines(headers, n) {
}
+// This function is used to help avoid the lowercasing of a field name if it
+// matches a 'traditional cased' version of a field name. It then returns the
+// lowercased name to both avoid calling toLowerCase() a second time and to
+// indicate whether the field was a 'no duplicates' field. If a field is not a
+// 'no duplicates' field, a `0` byte is prepended as a flag. The one exception
+// to this is the Set-Cookie header which is indicated by a `1` byte flag, since
+// it is an 'array' field and thus is treated differently in _addHeaderLines().
+// TODO: perhaps http_parser could be returning both raw and lowercased versions
+// of known header names to avoid us having to call toLowerCase() for those
+// headers.
+/* eslint-disable max-len */
+// 'array' header list is taken from:
+// https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
+/* eslint-enable max-len */
+function matchKnownFields(field) {
+ var low = false;
+ while (true) {
+ switch (field) {
+ case 'Content-Type':
+ case 'content-type':
+ return 'content-type';
+ case 'Content-Length':
+ case 'content-length':
+ return 'content-length';
+ case 'User-Agent':
+ case 'user-agent':
+ return 'user-agent';
+ case 'Referer':
+ case 'referer':
+ return 'referer';
+ case 'Host':
+ case 'host':
+ return 'host';
+ case 'Authorization':
+ case 'authorization':
+ return 'authorization';
+ case 'Proxy-Authorization':
+ case 'proxy-authorization':
+ return 'proxy-authorization';
+ case 'If-Modified-Since':
+ case 'if-modified-since':
+ return 'if-modified-since';
+ case 'If-Unmodified-Since':
+ case 'if-unmodified-since':
+ return 'if-unmodified-since';
+ case 'From':
+ case 'from':
+ return 'from';
+ case 'Location':
+ case 'location':
+ return 'location';
+ case 'Max-Forwards':
+ case 'max-forwards':
+ return 'max-forwards';
+ case 'Retry-After':
+ case 'retry-after':
+ return 'retry-after';
+ case 'ETag':
+ case 'etag':
+ return 'etag';
+ case 'Last-Modified':
+ case 'last-modified':
+ return 'last-modified';
+ case 'Server':
+ case 'server':
+ return 'server';
+ case 'Age':
+ case 'age':
+ return 'age';
+ case 'Expires':
+ case 'expires':
+ return 'expires';
+ case 'Set-Cookie':
+ case 'set-cookie':
+ return '\u0001';
+ // The fields below are not used in _addHeaderLine(), but they are common
+ // headers where we can avoid toLowerCase() if the mixed or lower case
+ // versions match the first time through.
+ case 'Transfer-Encoding':
+ case 'transfer-encoding':
+ return '\u0000transfer-encoding';
+ case 'Date':
+ case 'date':
+ return '\u0000date';
+ case 'Connection':
+ case 'connection':
+ return '\u0000connection';
+ case 'Cache-Control':
+ case 'cache-control':
+ return '\u0000cache-control';
+ case 'Vary':
+ case 'vary':
+ return '\u0000vary';
+ case 'Content-Encoding':
+ case 'content-encoding':
+ return '\u0000content-encoding';
+ case 'Cookie':
+ case 'cookie':
+ return '\u0000cookie';
+ case 'Origin':
+ case 'origin':
+ return '\u0000origin';
+ case 'Upgrade':
+ case 'upgrade':
+ return '\u0000upgrade';
+ case 'Expect':
+ case 'expect':
+ return '\u0000expect';
+ case 'If-Match':
+ case 'if-match':
+ return '\u0000if-match';
+ case 'If-None-Match':
+ case 'if-none-match':
+ return '\u0000if-none-match';
+ case 'Accept':
+ case 'accept':
+ return '\u0000accept';
+ case 'Accept-Encoding':
+ case 'accept-encoding':
+ return '\u0000accept-encoding';
+ case 'Accept-Language':
+ case 'accept-language':
+ return '\u0000accept-language';
+ case 'X-Forwarded-For':
+ case 'x-forwarded-for':
+ return '\u0000x-forwarded-for';
+ case 'X-Forwarded-Host':
+ case 'x-forwarded-host':
+ return '\u0000x-forwarded-host';
+ case 'X-Forwarded-Proto':
+ case 'x-forwarded-proto':
+ return '\u0000x-forwarded-proto';
+ default:
+ if (low)
+ return '\u0000' + field;
+ field = field.toLowerCase();
+ low = true;
+ }
+ }
+}
// Add the given (field, value) pair to the message
//
// Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
@@ -128,51 +268,27 @@ function _addHeaderLines(headers, n) {
// always joined.
IncomingMessage.prototype._addHeaderLine = _addHeaderLine;
function _addHeaderLine(field, value, dest) {
- field = field.toLowerCase();
- switch (field) {
- // Array headers:
- case 'set-cookie':
- if (dest[field] !== undefined) {
- dest[field].push(value);
- } else {
- dest[field] = [value];
- }
- break;
-
- /* eslint-disable max-len */
- // list is taken from:
- // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
- /* eslint-enable max-len */
- case 'content-type':
- case 'content-length':
- case 'user-agent':
- case 'referer':
- case 'host':
- case 'authorization':
- case 'proxy-authorization':
- case 'if-modified-since':
- case 'if-unmodified-since':
- case 'from':
- case 'location':
- case 'max-forwards':
- case 'retry-after':
- case 'etag':
- case 'last-modified':
- case 'server':
- case 'age':
- case 'expires':
- // drop duplicates
- if (dest[field] === undefined)
- dest[field] = value;
- break;
-
- default:
- // make comma-separated list
- if (typeof dest[field] === 'string') {
- dest[field] += ', ' + value;
- } else {
- dest[field] = value;
- }
+ field = matchKnownFields(field);
+ var flag = field.charCodeAt(0);
+ if (flag === 0) {
+ field = field.slice(1);
+ // Make comma-separated list
+ if (typeof dest[field] === 'string') {
+ dest[field] += ', ' + value;
+ } else {
+ dest[field] = value;
+ }
+ } else if (flag === 1) {
+ // Array header -- only Set-Cookie at the moment
+ if (dest['set-cookie'] !== undefined) {
+ dest['set-cookie'].push(value);
+ } else {
+ dest['set-cookie'] = [value];
+ }
+ } else {
+ // Drop duplicates
+ if (dest[field] === undefined)
+ dest[field] = value;
}
}