mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
Use flat object instead of array-of-arrays for HTTP headers.
E.G. { "Content-Length": 10, "Content-Type": "text/html" } instead of
[["Content-Length", 10], ["Content-Type", "text/html"]].
The main reason for this change is object-creation efficiency.
This still needs testing and some further changes (like when receiving
multiple header lines with the same field-name, they are concatenated with a
comma but some headers ("Content-Length") should not be concatenated ; the
new header line should replace the old value).
Various thoughts on this subject:
http://groups.google.com/group/nodejs/browse_thread/thread/9a67bb32706d9efc#
http://four.livejournal.com/979640.html
http://mail.gnome.org/archives/libsoup-list/2009-March/msg00015.html
This commit is contained in:
@@ -40,9 +40,9 @@ node.http.createServer(function (req, res) {
|
||||
var content_length = body.length.toString();
|
||||
|
||||
res.sendHeader( status
|
||||
, [ ["Content-Type", "text/plain"]
|
||||
, ["Content-Length", content_length]
|
||||
]
|
||||
, { "Content-Type": "text/plain"
|
||||
, "Content-Length": content_length
|
||||
}
|
||||
);
|
||||
res.sendBody(body);
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ for (var i = 0; i < bytes; i++) {
|
||||
}
|
||||
|
||||
var server = node.http.createServer(function (req, res) {
|
||||
res.sendHeader(200, [
|
||||
["Content-Type", "text/plain"],
|
||||
["Content-Length", body.length]
|
||||
]);
|
||||
res.sendHeader(200, {
|
||||
"Content-Type": "text/plain",
|
||||
"Content-Length": body.length
|
||||
});
|
||||
res.sendBody(body);
|
||||
res.finish();
|
||||
})
|
||||
|
||||
79
src/http.js
79
src/http.js
@@ -117,7 +117,7 @@ function IncomingMessage (connection) {
|
||||
|
||||
this.connection = connection;
|
||||
this.httpVersion = null;
|
||||
this.headers = [];
|
||||
this.headers = {};
|
||||
|
||||
// request (server) only
|
||||
this.uri = "";
|
||||
@@ -142,6 +142,15 @@ IncomingMessage.prototype.resume = function () {
|
||||
this.connection.readResume();
|
||||
};
|
||||
|
||||
IncomingMessage.prototype._addHeaderLine = function (field, value) {
|
||||
if (field in this.headers) {
|
||||
// TODO Certain headers like 'Content-Type' should not be concatinated.
|
||||
// See https://www.google.com/reader/view/?tab=my#overview-page
|
||||
this.headers[field] += ", " + value;
|
||||
} else {
|
||||
this.headers[field] = value;
|
||||
}
|
||||
};
|
||||
|
||||
function OutgoingMessage () {
|
||||
node.EventEmitter.call(this);
|
||||
@@ -162,22 +171,26 @@ OutgoingMessage.prototype.send = function (data, encoding) {
|
||||
this.output.push(data);
|
||||
};
|
||||
|
||||
OutgoingMessage.prototype.sendHeaderLines = function (first_line, header_lines) {
|
||||
OutgoingMessage.prototype.sendHeaderLines = function (first_line, headers) {
|
||||
var sent_connection_header = false;
|
||||
var sent_content_length_header = false;
|
||||
var sent_transfer_encoding_header = false;
|
||||
|
||||
header_lines = header_lines || [];
|
||||
|
||||
// first_line in the case of request is: "GET /index.html HTTP/1.1\r\n"
|
||||
// in the case of response it is: "HTTP/1.1 200 OK\r\n"
|
||||
var header = first_line;
|
||||
var message_header = first_line;
|
||||
var field, value;
|
||||
for (var i in headers) {
|
||||
if (headers instanceof Array) {
|
||||
field = headers[i][0];
|
||||
value = headers[i][1];
|
||||
} else {
|
||||
if (!headers.hasOwnProperty(i)) continue;
|
||||
field = i;
|
||||
value = headers[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < header_lines.length; i++) {
|
||||
var field = header_lines[i][0];
|
||||
var value = header_lines[i][1];
|
||||
|
||||
header += field + ": " + value + CRLF;
|
||||
message_header += field + ": " + value + CRLF;
|
||||
|
||||
if (connection_expression.exec(field)) {
|
||||
sent_connection_header = true;
|
||||
@@ -196,23 +209,23 @@ OutgoingMessage.prototype.sendHeaderLines = function (first_line, header_lines)
|
||||
// keep-alive logic
|
||||
if (sent_connection_header == false) {
|
||||
if (this.should_keep_alive) {
|
||||
header += "Connection: keep-alive\r\n";
|
||||
message_header += "Connection: keep-alive\r\n";
|
||||
} else {
|
||||
this.closeOnFinish = true;
|
||||
header += "Connection: close\r\n";
|
||||
message_header += "Connection: close\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (sent_content_length_header == false && sent_transfer_encoding_header == false) {
|
||||
if (this.use_chunked_encoding_by_default) {
|
||||
header += "Transfer-Encoding: chunked\r\n";
|
||||
message_header += "Transfer-Encoding: chunked\r\n";
|
||||
this.chunked_encoding = true;
|
||||
}
|
||||
}
|
||||
|
||||
header += CRLF;
|
||||
message_header += CRLF;
|
||||
|
||||
this.send(header);
|
||||
this.send(message_header);
|
||||
// wait until the first body chunk, or finish(), is sent to flush.
|
||||
};
|
||||
|
||||
@@ -255,7 +268,7 @@ ServerResponse.prototype.sendHeader = function (statusCode, headers) {
|
||||
};
|
||||
|
||||
|
||||
function ClientRequest (method, uri, header_lines) {
|
||||
function ClientRequest (method, uri, headers) {
|
||||
OutgoingMessage.call(this);
|
||||
|
||||
this.should_keep_alive = false;
|
||||
@@ -266,7 +279,7 @@ function ClientRequest (method, uri, header_lines) {
|
||||
}
|
||||
this.closeOnFinish = true;
|
||||
|
||||
this.sendHeaderLines(method + " " + uri + " HTTP/1.1\r\n", header_lines);
|
||||
this.sendHeaderLines(method + " " + uri + " HTTP/1.1\r\n", headers);
|
||||
}
|
||||
node.inherits(ClientRequest, OutgoingMessage);
|
||||
|
||||
@@ -282,7 +295,7 @@ function createIncomingMessageStream (connection, incoming_listener) {
|
||||
stream.addListener("incoming", incoming_listener);
|
||||
|
||||
var incoming;
|
||||
var last_header_was_a_value = false;
|
||||
var field = null, value = null;
|
||||
|
||||
connection.addListener("message_begin", function () {
|
||||
incoming = new IncomingMessage(connection);
|
||||
@@ -294,25 +307,31 @@ function createIncomingMessageStream (connection, incoming_listener) {
|
||||
});
|
||||
|
||||
connection.addListener("header_field", function (data) {
|
||||
if (incoming.headers.length > 0 && last_header_was_a_value == false) {
|
||||
incoming.headers[incoming.headers.length-1][0] += data;
|
||||
} else {
|
||||
incoming.headers.push([data]);
|
||||
if (value) {
|
||||
incoming._addHeaderLine(field, value);
|
||||
field = null;
|
||||
value = null;
|
||||
}
|
||||
if (field) {
|
||||
field += data;
|
||||
} else {
|
||||
field = data;
|
||||
}
|
||||
last_header_was_a_value = false;
|
||||
});
|
||||
|
||||
connection.addListener("header_value", function (data) {
|
||||
var last_pair = incoming.headers[incoming.headers.length-1];
|
||||
if (last_pair.length == 1) {
|
||||
last_pair[1] = data;
|
||||
} else {
|
||||
last_pair[1] += data;
|
||||
}
|
||||
last_header_was_a_value = true;
|
||||
if (value) {
|
||||
value += data;
|
||||
} else {
|
||||
value = data;
|
||||
}
|
||||
});
|
||||
|
||||
connection.addListener("headers_complete", function (info) {
|
||||
if (field && value) {
|
||||
incoming._addHeaderLine(field, value);
|
||||
}
|
||||
|
||||
incoming.httpVersion = info.httpVersion;
|
||||
|
||||
if (info.method) {
|
||||
|
||||
@@ -5,7 +5,7 @@ var request_count = 1000;
|
||||
var response_body = '{"ok": true}';
|
||||
|
||||
var server = node.http.createServer(function(req, res) {
|
||||
res.sendHeader(200, [['Content-Type', 'text/javascript']]);
|
||||
res.sendHeader(200, {'Content-Type': 'text/javascript'});
|
||||
res.sendBody(response_body);
|
||||
res.finish();
|
||||
});
|
||||
|
||||
@@ -6,10 +6,9 @@ var body2_s = "22222";
|
||||
|
||||
var server = node.http.createServer(function (req, res) {
|
||||
var body = req.uri.path === "/1" ? body1_s : body2_s;
|
||||
res.sendHeader(200, [
|
||||
["Content-Type", "text/plain"],
|
||||
["Content-Length", body.length]
|
||||
]);
|
||||
res.sendHeader(200, { "Content-Type": "text/plain"
|
||||
, "Content-Length": body.length
|
||||
});
|
||||
res.sendBody(body);
|
||||
res.finish();
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ var server = node.http.createServer(function(req, res) {
|
||||
req.addListener("complete", function () {
|
||||
server_req_complete = true;
|
||||
puts("request complete from server");
|
||||
res.sendHeader(200, [['Content-Type', 'text/plain']]);
|
||||
res.sendHeader(200, {'Content-Type': 'text/plain'});
|
||||
res.sendBody('hello\n');
|
||||
res.finish();
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ var BACKEND_PORT = 8870;
|
||||
|
||||
var backend = node.http.createServer(function (req, res) {
|
||||
// node.debug("backend");
|
||||
res.sendHeader(200, [["content-type", "text/plain"]]);
|
||||
res.sendHeader(200, {"content-type": "text/plain"});
|
||||
res.sendBody("hello world\n");
|
||||
res.finish();
|
||||
});
|
||||
@@ -14,7 +14,7 @@ backend.listen(BACKEND_PORT);
|
||||
|
||||
var proxy_client = node.http.createClient(BACKEND_PORT);
|
||||
var proxy = node.http.createServer(function (req, res) {
|
||||
// node.debug("proxy req");
|
||||
node.debug("proxy req headers: " + JSON.stringify(req.headers));
|
||||
var proxy_req = proxy_client.get(req.uri.path);
|
||||
proxy_req.finish(function(proxy_res) {
|
||||
res.sendHeader(proxy_res.statusCode, proxy_res.headers);
|
||||
|
||||
@@ -26,7 +26,7 @@ function onLoad() {
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
res.sendHeader(200, [["Content-Type", "text/plain"]]);
|
||||
res.sendHeader(200, {"Content-Type": "text/plain"});
|
||||
res.sendBody(req.uri.path);
|
||||
res.finish();
|
||||
}, 1);
|
||||
|
||||
@@ -11,6 +11,13 @@ function onLoad () {
|
||||
if (responses_sent == 0) {
|
||||
assertEquals("GET", req.method);
|
||||
assertEquals("/hello", req.uri.path);
|
||||
|
||||
p(req.headers);
|
||||
assertTrue("Accept" in req.headers);
|
||||
assertEquals("*/*", req.headers["Accept"]);
|
||||
|
||||
assertTrue("Foo" in req.headers);
|
||||
assertEquals("bar", req.headers["Foo"]);
|
||||
}
|
||||
|
||||
if (responses_sent == 1) {
|
||||
@@ -20,7 +27,7 @@ function onLoad () {
|
||||
}
|
||||
|
||||
req.addListener("complete", function () {
|
||||
res.sendHeader(200, [["Content-Type", "text/plain"]]);
|
||||
res.sendHeader(200, {"Content-Type": "text/plain"});
|
||||
res.sendBody("The path was " + req.uri.path);
|
||||
res.finish();
|
||||
responses_sent += 1;
|
||||
@@ -30,7 +37,7 @@ function onLoad () {
|
||||
}).listen(PORT);
|
||||
|
||||
var client = node.http.createClient(PORT);
|
||||
var req = client.get("/hello");
|
||||
var req = client.get("/hello", {"Accept": "*/*", "Foo": "bar"});
|
||||
req.finish(function (res) {
|
||||
assertEquals(200, res.statusCode);
|
||||
responses_recvd += 1;
|
||||
|
||||
@@ -18,7 +18,7 @@ World" after waiting two seconds:
|
||||
----------------------------------------
|
||||
node.http.createServer(function (request, response) {
|
||||
setTimeout(function () {
|
||||
response.sendHeader(200, [["Content-Type", "text/plain"]]);
|
||||
response.sendHeader(200, {"Content-Type": "text/plain"});
|
||||
response.sendBody("Hello World");
|
||||
response.finish();
|
||||
}, 2000);
|
||||
@@ -575,15 +575,14 @@ In particular, large, possibly chunk-encoded, messages. The interface is
|
||||
careful to never buffer entire requests or responses--the
|
||||
user is able to stream data.
|
||||
|
||||
HTTP message headers are represented by an array of 2-element
|
||||
arrays like this
|
||||
HTTP message headers are represented by an object like this
|
||||
|
||||
----------------------------------------
|
||||
[ ["Content-Length", "123"]
|
||||
, ["Content-Type", "text/plain"]
|
||||
, ["Connection", "keep-alive"]
|
||||
, ["Accept", "*/*"]
|
||||
]
|
||||
{ "Content-Length": "123"
|
||||
, "Content-Type": "text/plain"
|
||||
, "Connection": "keep-alive"
|
||||
, "Accept": "*/*"
|
||||
}
|
||||
----------------------------------------
|
||||
|
||||
In order to support the full spectrum of possible HTTP applications, Node's
|
||||
@@ -693,7 +692,6 @@ in the actual HTTP Request.
|
||||
|
||||
|
||||
+request.headers+ ::
|
||||
The request headers expressed as an array of 2-element arrays.
|
||||
Read only.
|
||||
|
||||
|
||||
@@ -727,17 +725,16 @@ passed as the second parameter to the +"request"+ event.
|
||||
+response.sendHeader(statusCode, headers)+ ::
|
||||
|
||||
Sends a response header to the request. The status code is a 3-digit HTTP
|
||||
status code, like +404+. The second argument, +headers+, should be an array
|
||||
of 2-element arrays, representing the response headers.
|
||||
status code, like +404+. The second argument, +headers+ are the response headers.
|
||||
+
|
||||
Example:
|
||||
+
|
||||
----------------------------------------
|
||||
var body = "hello world";
|
||||
response.sendHeader(200, [
|
||||
["Content-Length", body.length],
|
||||
["Content-Type", "text/plain"]
|
||||
]);
|
||||
response.sendHeader(200, {
|
||||
"Content-Length": body.length,
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
----------------------------------------
|
||||
+
|
||||
This method must only be called once on a message and it must
|
||||
@@ -799,8 +796,7 @@ connection is not established until a request is issued.
|
||||
Issues a request; if necessary establishes connection. Returns a +node.http.ClientRequest+ instance.
|
||||
+
|
||||
+request_headers+ is optional.
|
||||
+request_headers+ should be an array of 2-element
|
||||
arrays. Additional request headers might be added internally
|
||||
Additional request headers might be added internally
|
||||
by Node. Returns a +ClientRequest+ object.
|
||||
+
|
||||
Do remember to include the +Content-Length+ header if you
|
||||
@@ -894,7 +890,7 @@ After emitted no other events will be emitted on the response.
|
||||
+"1.1"+ or +"1.0"+.
|
||||
|
||||
+response.headers+ ::
|
||||
The response headers. An Array of 2-element arrays.
|
||||
The response headers.
|
||||
|
||||
+response.setBodyEncoding(encoding)+ ::
|
||||
Set the encoding for the response body. Either +"utf8"+ or +"raw"+.
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<pre>
|
||||
node.http.createServer(function (req, res) {
|
||||
setTimeout(function () {
|
||||
res.sendHeader(200, [["Content-Type", "text/plain"]]);
|
||||
res.sendHeader(200, {"Content-Type": "text/plain"});
|
||||
res.sendBody("Hello World");
|
||||
res.finish();
|
||||
}, 2000);
|
||||
|
||||
Reference in New Issue
Block a user