summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWeijia Wang <381152119@qq.com>2019-02-11 13:30:15 +0800
committerWeijia Wang <381152119@qq.com>2019-02-13 21:25:20 +0800
commitda0dc51e396ea4a1f12f259a8149f4177ad674e8 (patch)
tree2683a1c1f33b8eaa55e5bb528f4cc2e016972690
parent8ecf313324e619d7211adaee76c6b7bb1882e12b (diff)
downloadandroid-node-v8-da0dc51e396ea4a1f12f259a8149f4177ad674e8.tar.gz
android-node-v8-da0dc51e396ea4a1f12f259a8149f4177ad674e8.tar.bz2
android-node-v8-da0dc51e396ea4a1f12f259a8149f4177ad674e8.zip
http: improve performance for incoming headers
PR-URL: https://github.com/nodejs/node/pull/26041 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
-rw-r--r--benchmark/_http-benchmarkers.js5
-rw-r--r--benchmark/http/incoming_headers.js35
-rw-r--r--lib/_http_incoming.js202
3 files changed, 124 insertions, 118 deletions
diff --git a/benchmark/_http-benchmarkers.js b/benchmark/_http-benchmarkers.js
index f456628454..a4d6230039 100644
--- a/benchmark/_http-benchmarkers.js
+++ b/benchmark/_http-benchmarkers.js
@@ -25,8 +25,11 @@ class AutocannonBenchmarker {
'-c', options.connections,
'-j',
'-n',
- `http://127.0.0.1:${options.port}${options.path}`,
];
+ for (const field in options.headers) {
+ args.push('-H', `${field}=${options.headers[field]}`);
+ }
+ args.push(`http://127.0.0.1:${options.port}${options.path}`);
const child = child_process.spawn(this.executable, args);
return child;
}
diff --git a/benchmark/http/incoming_headers.js b/benchmark/http/incoming_headers.js
new file mode 100644
index 0000000000..a1ab57e238
--- /dev/null
+++ b/benchmark/http/incoming_headers.js
@@ -0,0 +1,35 @@
+'use strict';
+const common = require('../common.js');
+const http = require('http');
+
+const bench = common.createBenchmark(main, {
+ // unicode confuses ab on os x.
+ c: [50, 500],
+ headerDuplicates: [0, 5, 20]
+});
+
+function main({ c, headerDuplicates }) {
+ const server = http.createServer((req, res) => {
+ res.end();
+ });
+
+ server.listen(common.PORT, () => {
+ const headers = {
+ 'Content-Type': 'text/plain',
+ 'Accept': 'text/plain',
+ 'User-Agent': 'nodejs-benchmark',
+ 'Date': new Date().toString(),
+ 'Cache-Control': 'no-cache'
+ };
+ for (let i = 0; i < headerDuplicates; i++) {
+ headers[`foo${i}`] = `some header value ${i}`;
+ }
+ bench.http({
+ path: '/',
+ connections: c,
+ headers
+ }, () => {
+ server.close();
+ });
+ });
+}
diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js
index 1e0c42f7bd..7ba4d366b2 100644
--- a/lib/_http_incoming.js
+++ b/lib/_http_incoming.js
@@ -134,133 +134,101 @@ function _addHeaderLines(headers, n) {
// 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.
-
-// 'array' header list is taken from:
-// https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp
-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':
+function matchKnownFields(field, lowercased) {
+ switch (field.length) {
+ case 3:
+ if (field === 'Age' || field === 'age') return 'age';
+ break;
+ case 4:
+ if (field === 'Host' || field === 'host') return 'host';
+ if (field === 'From' || field === 'from') return 'from';
+ if (field === 'ETag' || field === 'etag') return 'etag';
+ if (field === 'Date' || field === 'date') return '\u0000date';
+ if (field === 'Vary' || field === 'vary') return '\u0000vary';
+ break;
+ case 6:
+ if (field === 'Server' || field === 'server') return 'server';
+ if (field === 'Cookie' || field === 'cookie') return '\u0002cookie';
+ if (field === 'Origin' || field === 'origin') return '\u0000origin';
+ if (field === 'Expect' || field === 'expect') return '\u0000expect';
+ if (field === 'Accept' || field === 'accept') return '\u0000accept';
+ break;
+ case 7:
+ if (field === 'Referer' || field === 'referer') return 'referer';
+ if (field === 'Expires' || field === 'expires') return 'expires';
+ if (field === 'Upgrade' || field === 'upgrade') return '\u0000upgrade';
+ break;
+ case 8:
+ if (field === 'Location' || field === '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':
+ if (field === 'If-Match' || field === 'if-match')
+ return '\u0000if-match';
+ break;
+ case 10:
+ if (field === 'User-Agent' || field === 'user-agent')
+ return 'user-agent';
+ if (field === 'Set-Cookie' || field === 'set-cookie')
return '\u0001';
- case 'Cookie':
- case 'cookie':
- return '\u0002cookie';
- // 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':
+ if (field === 'Connection' || field === 'connection')
return '\u0000connection';
- case 'Cache-Control':
- case 'cache-control':
+ break;
+ case 11:
+ if (field === 'Retry-After' || field === 'retry-after')
+ return 'retry-after';
+ break;
+ case 12:
+ if (field === 'Content-Type' || field === 'content-type')
+ return 'content-type';
+ if (field === 'Max-Forwards' || field === 'max-forwards')
+ return 'max-forwards';
+ break;
+ case 13:
+ if (field === 'Authorization' || field === 'authorization')
+ return 'authorization';
+ if (field === 'Last-Modified' || field === 'last-modified')
+ return 'last-modified';
+ if (field === 'Cache-Control' || field === 'cache-control')
return '\u0000cache-control';
- case 'Vary':
- case 'vary':
- return '\u0000vary';
- case 'Content-Encoding':
- case 'content-encoding':
- return '\u0000content-encoding';
- 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':
+ if (field === 'If-None-Match' || field === 'if-none-match')
return '\u0000if-none-match';
- case 'Accept':
- case 'accept':
- return '\u0000accept';
- case 'Accept-Encoding':
- case 'accept-encoding':
+ break;
+ case 14:
+ if (field === 'Content-Length' || field === 'content-length')
+ return 'content-length';
+ break;
+ case 15:
+ if (field === 'Accept-Encoding' || field === 'accept-encoding')
return '\u0000accept-encoding';
- case 'Accept-Language':
- case 'accept-language':
+ if (field === 'Accept-Language' || field === 'accept-language')
return '\u0000accept-language';
- case 'X-Forwarded-For':
- case 'x-forwarded-for':
+ if (field === 'X-Forwarded-For' || field === 'x-forwarded-for')
return '\u0000x-forwarded-for';
- case 'X-Forwarded-Host':
- case 'x-forwarded-host':
+ break;
+ case 16:
+ if (field === 'Content-Encoding' || field === 'content-encoding')
+ return '\u0000content-encoding';
+ if (field === 'X-Forwarded-Host' || field === 'x-forwarded-host')
return '\u0000x-forwarded-host';
- case 'X-Forwarded-Proto':
- case 'x-forwarded-proto':
+ break;
+ case 17:
+ if (field === 'If-Modified-Since' || field === 'if-modified-since')
+ return 'if-modified-since';
+ if (field === 'Transfer-Encoding' || field === 'transfer-encoding')
+ return '\u0000transfer-encoding';
+ if (field === 'X-Forwarded-Proto' || field === 'x-forwarded-proto')
return '\u0000x-forwarded-proto';
- default:
- if (low)
- return '\u0000' + field;
- field = field.toLowerCase();
- low = true;
- }
+ break;
+ case 19:
+ if (field === 'Proxy-Authorization' || field === 'proxy-authorization')
+ return 'proxy-authorization';
+ if (field === 'If-Unmodified-Since' || field === 'if-unmodified-since')
+ return 'if-unmodified-since';
+ break;
+ }
+ if (lowercased) {
+ return '\u0000' + field;
+ } else {
+ return matchKnownFields(field.toLowerCase(), true);
}
}
// Add the given (field, value) pair to the message