From dcf51274ce0953e577fbfffd81afb592319a2267 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Wed, 19 Dec 2018 15:56:30 +0300 Subject: Node.js: checking uniqueness of HTTP headers for different case. --- src/nodejs/unit-http/http_server.js | 72 +++++++++++++++++++++++++------------ src/nodejs/unit-http/unit.cpp | 14 ++++++-- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index 28f2303f..216c4394 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -47,24 +47,23 @@ ServerResponse.prototype.writeContinue = function writeContinue(cb) { ServerResponse.prototype.writeProcessing = function writeProcessing(cb) { }; -ServerResponse.prototype.setHeader = function setHeader(key, value) { - if (typeof key !== 'string') { - throw new TypeError('Key argument must be a string'); +ServerResponse.prototype.setHeader = function setHeader(name, value) { + if (typeof name !== 'string') { + throw new TypeError('Name argument must be a string'); } - let header_key_len = Buffer.byteLength(key, 'latin1'); - let header_len = 0 - let header_count = 0; + let value_len = 0 + let count = 0; if (Array.isArray(value)) { - header_count = value.length; + count = value.length; value.forEach(function(val) { if (typeof val !== 'string' && typeof val !== 'number') { throw new TypeError('Array entries must be string or number'); } - header_len += Buffer.byteLength(val + "", 'latin1'); + value_len += Buffer.byteLength(val + "", 'latin1'); }); } else { @@ -72,19 +71,27 @@ ServerResponse.prototype.setHeader = function setHeader(key, value) { throw new TypeError('Value argument must be string, number, or array'); } - header_count = 1; - header_len = Buffer.byteLength(value + "", 'latin1'); + count = 1; + value_len = Buffer.byteLength(value + "", 'latin1'); } - this.removeHeader(key); + let lc_name = name.toLowerCase(); - this.headers[key] = value; - this.headers_len += header_len + (header_key_len * header_count); - this.headers_count += header_count; + if (lc_name in this.headers) { + this._removeHeader(lc_name); + } + + let name_len = Buffer.byteLength(name, 'latin1'); + + this.headers[lc_name] = [name, value]; + this.headers_len += value_len + (name_len * count); + this.headers_count += count; }; ServerResponse.prototype.getHeader = function getHeader(name) { - return this.headers[name]; + const entry = this.headers[name.toLowerCase()]; + + return entry && entry[1]; }; ServerResponse.prototype.getHeaderNames = function getHeaderNames() { @@ -92,22 +99,43 @@ ServerResponse.prototype.getHeaderNames = function getHeaderNames() { }; ServerResponse.prototype.getHeaders = function getHeaders() { - return this.headers; + const ret = Object.create(null); + + if (this.headers) { + const keys = Object.keys(this.headers); + + for (var i = 0; i < keys.length; i++) { + const key = keys[i]; + + ret[key] = this.headers[key][1]; + } + } + + return ret; }; ServerResponse.prototype.hasHeader = function hasHeader(name) { - return name in this.headers; + return name.toLowerCase() in this.headers; }; ServerResponse.prototype.removeHeader = function removeHeader(name) { - if (!(name in this.headers)) { - return; + if (typeof name !== 'string') { + throw new TypeError('Name argument must be a string'); } - let name_len = Buffer.byteLength(name + "", 'latin1'); - let value = this.headers[name]; + let lc_name = name.toLowerCase(); + + if (lc_name in this.headers) { + this._removeHeader(lc_name); + } +}; + +ServerResponse.prototype._removeHeader = function _removeHeader(lc_name) { + let entry = this.headers[lc_name]; + let name_len = Buffer.byteLength(entry[0] + "", 'latin1'); + let value = entry[1]; - delete this.headers[name]; + delete this.headers[lc_name]; if (Array.isArray(value)) { this.headers_count -= value.length; diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index b233359c..36bc98db 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -737,7 +737,7 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) uint32_t keys_count, i, j; uint16_t hash; napi_value this_arg, headers, keys, name, value, array_val; - napi_value req_num; + napi_value req_num, array_entry; napi_status status; napi_valuetype val_type; nxt_unit_field_t *f; @@ -814,7 +814,17 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) goto failed; } - status = napi_get_property(env, headers, name, &value); + status = napi_get_property(env, headers, name, &array_entry); + if (status != napi_ok) { + goto failed; + } + + status = napi_get_element(env, array_entry, 0, &name); + if (status != napi_ok) { + goto failed; + } + + status = napi_get_element(env, array_entry, 1, &value); if (status != napi_ok) { goto failed; } -- cgit