diff --git a/doc/api.markdown b/doc/api.markdown index f7563b5362..66d83ce2e5 100644 --- a/doc/api.markdown +++ b/doc/api.markdown @@ -1791,6 +1791,10 @@ you can use the `require('querystring').parse` function, or pass Read only. +### request.trailers + +Read only; HTTP trailers (if present). Only populated after the 'end' event. + ### request.httpVersion 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. +### response.trailers + +The response trailers object. Only populated after the 'end' event. + ### response.setEncoding(encoding=null) Set the encoding for the response body. Either `'utf8'`, `'ascii'`, or `'base64'`. diff --git a/lib/http.js b/lib/http.js old mode 100644 new mode 100755 index 15c1a1fbc6..d7ccc260f1 --- a/lib/http.js +++ b/lib/http.js @@ -60,6 +60,8 @@ var parsers = new FreeList('parsers', 1000, function () { parser.onHeadersComplete = function (info) { if (parser.field && (parser.value != undefined)) { parser.incoming._addHeaderLine(parser.field, parser.value); + parser.field = null; + parser.value = null; } parser.incoming.httpVersionMajor = info.versionMajor; @@ -101,6 +103,10 @@ var parsers = new FreeList('parsers', 1000, 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) { // For upgraded connections, also emit this after parser.execute parser.incoming.emit("end"); @@ -183,7 +189,9 @@ function IncomingMessage (socket) { this.connection = socket; this.httpVersion = null; + this.complete = false; this.headers = {}; + this.trailers = {}; // request (server) only this.url = ""; @@ -223,13 +231,19 @@ IncomingMessage.prototype.resume = function () { // and drop the second. Extended header fields (those beginning with 'x-') are // always joined. IncomingMessage.prototype._addHeaderLine = function (field, value) { + var dest; + if (this.complete) { + dest = this.trailers + } else { + dest = this.headers + } switch (field) { // Array headers: case 'set-cookie': - if (field in this.headers) { - this.headers[field].push(value); + if (field in dest) { + dest[field].push(value); } else { - this.headers[field] = [value]; + dest[field] = [value]; } break; @@ -240,10 +254,10 @@ IncomingMessage.prototype._addHeaderLine = function (field, value) { case 'accept-language': case 'connection': case 'cookie': - if (field in this.headers) { - this.headers[field] += ', ' + value; + if (field in dest) { + dest[field] += ', ' + value; } else { - this.headers[field] = value; + dest[field] = value; } break; @@ -251,14 +265,14 @@ IncomingMessage.prototype._addHeaderLine = function (field, value) { default: if (field.slice(0,2) == 'x-') { // except for x- - if (field in this.headers) { - this.headers[field] += ', ' + value; + if (field in dest) { + dest[field] += ', ' + value; } else { - this.headers[field] = value; + dest[field] = value; } } else { // drop duplicates - if (!(field in this.headers)) this.headers[field] = value; + if (!(field in dest)) dest[field] = value; } break; } diff --git a/test/simple/test-http-set-trailers.js b/test/simple/test-http-set-trailers.js index 6b6a34c8df..e5c6438985 100644 --- a/test/simple/test-http-set-trailers.js +++ b/test/simple/test-http-set-trailers.js @@ -62,14 +62,33 @@ server.addListener("listening", function() { outstanding_reqs--; clearTimeout(tid); assert.ok( - /0\r\nx-foo: bar\r\n\r\n$/.test(res_buffer), + /0\r\nx-foo: bar\r\n\r\n$/.test(res_buffer), "No trailer in HTTP/1.1 response." - ); + ); if (outstanding_reqs == 0) { server.close(); process.exit(); } } }); +}); +// 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(); + } + }); + }); });