Browse Source

Consume HTTP trailing headers

v0.7.4-release
Mark Nottingham 14 years ago
committed by Ryan Dahl
parent
commit
1b24fc6678
  1. 8
      doc/api.markdown
  2. 34
      lib/http.js
  3. 19
      test/simple/test-http-set-trailers.js

8
doc/api.markdown

@ -1791,6 +1791,10 @@ you can use the `require('querystring').parse` function, or pass
Read only. Read only.
### request.trailers
Read only; HTTP trailers (if present). Only populated after the 'end' event.
### request.httpVersion ### request.httpVersion
The HTTP protocol version as a string. Read only. Examples: The HTTP protocol version as a string. Read only. Examples:
@ -2093,6 +2097,10 @@ Also `response.httpVersionMajor` is the first integer and
The response headers object. The response headers object.
### response.trailers
The response trailers object. Only populated after the 'end' event.
### response.setEncoding(encoding=null) ### response.setEncoding(encoding=null)
Set the encoding for the response body. Either `'utf8'`, `'ascii'`, or `'base64'`. Set the encoding for the response body. Either `'utf8'`, `'ascii'`, or `'base64'`.

34
lib/http.js

@ -60,6 +60,8 @@ var parsers = new FreeList('parsers', 1000, function () {
parser.onHeadersComplete = function (info) { parser.onHeadersComplete = function (info) {
if (parser.field && (parser.value != undefined)) { if (parser.field && (parser.value != undefined)) {
parser.incoming._addHeaderLine(parser.field, parser.value); parser.incoming._addHeaderLine(parser.field, parser.value);
parser.field = null;
parser.value = null;
} }
parser.incoming.httpVersionMajor = info.versionMajor; parser.incoming.httpVersionMajor = info.versionMajor;
@ -101,6 +103,10 @@ var parsers = new FreeList('parsers', 1000, function () {
}; };
parser.onMessageComplete = function () { parser.onMessageComplete = function () {
this.incoming.complete = true;
if (parser.field && (parser.value != undefined)) {
parser.incoming._addHeaderLine(parser.field, parser.value);
}
if (!parser.incoming.upgrade) { if (!parser.incoming.upgrade) {
// For upgraded connections, also emit this after parser.execute // For upgraded connections, also emit this after parser.execute
parser.incoming.emit("end"); parser.incoming.emit("end");
@ -183,7 +189,9 @@ function IncomingMessage (socket) {
this.connection = socket; this.connection = socket;
this.httpVersion = null; this.httpVersion = null;
this.complete = false;
this.headers = {}; this.headers = {};
this.trailers = {};
// request (server) only // request (server) only
this.url = ""; this.url = "";
@ -223,13 +231,19 @@ IncomingMessage.prototype.resume = function () {
// and drop the second. Extended header fields (those beginning with 'x-') are // and drop the second. Extended header fields (those beginning with 'x-') are
// always joined. // always joined.
IncomingMessage.prototype._addHeaderLine = function (field, value) { IncomingMessage.prototype._addHeaderLine = function (field, value) {
var dest;
if (this.complete) {
dest = this.trailers
} else {
dest = this.headers
}
switch (field) { switch (field) {
// Array headers: // Array headers:
case 'set-cookie': case 'set-cookie':
if (field in this.headers) { if (field in dest) {
this.headers[field].push(value); dest[field].push(value);
} else { } else {
this.headers[field] = [value]; dest[field] = [value];
} }
break; break;
@ -240,10 +254,10 @@ IncomingMessage.prototype._addHeaderLine = function (field, value) {
case 'accept-language': case 'accept-language':
case 'connection': case 'connection':
case 'cookie': case 'cookie':
if (field in this.headers) { if (field in dest) {
this.headers[field] += ', ' + value; dest[field] += ', ' + value;
} else { } else {
this.headers[field] = value; dest[field] = value;
} }
break; break;
@ -251,14 +265,14 @@ IncomingMessage.prototype._addHeaderLine = function (field, value) {
default: default:
if (field.slice(0,2) == 'x-') { if (field.slice(0,2) == 'x-') {
// except for x- // except for x-
if (field in this.headers) { if (field in dest) {
this.headers[field] += ', ' + value; dest[field] += ', ' + value;
} else { } else {
this.headers[field] = value; dest[field] = value;
} }
} else { } else {
// drop duplicates // drop duplicates
if (!(field in this.headers)) this.headers[field] = value; if (!(field in dest)) dest[field] = value;
} }
break; break;
} }

19
test/simple/test-http-set-trailers.js

@ -71,5 +71,24 @@ server.addListener("listening", function() {
} }
} }
}); });
});
// now, see if the client sees the trailers.
server.addListener('listening', function() {
var client = http.createClient(common.PORT);
var req = client.request("/hello", {});
req.end();
outstanding_reqs++;
req.addListener('response', function (res) {
res.addListener('end', function () {
// console.log(res.trailers);
assert.ok("x-foo" in res.trailers,
"Client doesn't see trailers.");
outstanding_reqs--;
if (outstanding_reqs == 0) {
server.close();
process.exit();
}
});
});
}); });

Loading…
Cancel
Save