mirror of https://github.com/nodejs/node.git
Support for outgoing HTTP trailing headers
parent
83ff473d30
commit
4fe3007a1a
|
@ -1894,6 +1894,24 @@ header information and the first body to the client. The second time
|
|||
data, and sends that separately. That is, the response is buffered up to the
|
||||
first chunk of body.
|
||||
|
||||
### response.addTrailers(headers)
|
||||
|
||||
This method adds HTTP trailing headers (a header but at the end of the
|
||||
message) to the response.
|
||||
|
||||
Trailers will **only** be emitted if chunked encoding is used for the
|
||||
response; if it is not (e.g., if the request was HTTP/1.0), they will
|
||||
be silently discarded.
|
||||
|
||||
Note that HTTP requires the `Trailer` header to be sent if you intend to
|
||||
emit trailers, with a list of the header fields in its value. E.g.,
|
||||
|
||||
response.writeHead(200, { 'Content-Type': 'text/plain',
|
||||
'Trailer': 'TraceInfo' });
|
||||
response.write(fileData);
|
||||
response.addTrailers({'Content-MD5': "7895bf4b8828b55ceaf47747b4bca667"});
|
||||
response.end();
|
||||
|
||||
|
||||
### response.end([data], [encoding])
|
||||
|
||||
|
|
27
lib/http.js
27
lib/http.js
|
@ -292,6 +292,7 @@ function OutgoingMessage (socket) {
|
|||
this.useChunkedEncodingByDefault = true;
|
||||
|
||||
this._hasBody = true;
|
||||
this._trailer = '';
|
||||
|
||||
this.finished = false;
|
||||
}
|
||||
|
@ -484,6 +485,26 @@ OutgoingMessage.prototype.write = function (chunk, encoding) {
|
|||
return ret;
|
||||
};
|
||||
|
||||
|
||||
OutgoingMessage.prototype.addTrailers = function (headers) {
|
||||
this._trailer = "";
|
||||
var keys = Object.keys(headers);
|
||||
var isArray = (Array.isArray(headers));
|
||||
for (var i = 0, l = keys.length; i < l; i++) {
|
||||
var key = keys[i];
|
||||
if (isArray) {
|
||||
field = headers[key][0];
|
||||
value = headers[key][1];
|
||||
} else {
|
||||
field = key;
|
||||
value = headers[key];
|
||||
}
|
||||
|
||||
this._trailer += field + ": " + value + CRLF;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
OutgoingMessage.prototype.finish = function () {
|
||||
throw new Error("finish() has been renamed to close().");
|
||||
};
|
||||
|
@ -520,7 +541,9 @@ OutgoingMessage.prototype.end = function (data, encoding) {
|
|||
+ l
|
||||
+ CRLF
|
||||
+ data
|
||||
+ "\r\n0\r\n\r\n"
|
||||
+ "\r\n0\r\n"
|
||||
+ this._trailer
|
||||
+ "\r\n"
|
||||
, encoding
|
||||
);
|
||||
} else {
|
||||
|
@ -535,7 +558,7 @@ OutgoingMessage.prototype.end = function (data, encoding) {
|
|||
|
||||
if (!hot) {
|
||||
if (this.chunkedEncoding) {
|
||||
ret = this._send('0\r\n\r\n'); // Last chunk.
|
||||
ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk.
|
||||
} else if (!data) {
|
||||
// Force a flush, HACK.
|
||||
ret = this._send('');
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
common = require("../common");
|
||||
assert = common.assert;
|
||||
http = require("http");
|
||||
net = require("net");
|
||||
|
||||
outstanding_reqs = 0;
|
||||
|
||||
var server = http.createServer(function(req, res) {
|
||||
res.writeHead(200, [ ['content-type', 'text/plain'] ]);
|
||||
res.addTrailers({"x-foo": "bar"});
|
||||
res.end("stuff" + "\n");
|
||||
});
|
||||
server.listen(common.PORT);
|
||||
|
||||
|
||||
// first, we test an HTTP/1.0 request.
|
||||
server.addListener("listening", function() {
|
||||
var c = net.createConnection(common.PORT);
|
||||
var res_buffer = "";
|
||||
|
||||
c.setEncoding("utf8");
|
||||
|
||||
c.addListener("connect", function () {
|
||||
outstanding_reqs++;
|
||||
c.write( "GET / HTTP/1.0\r\n\r\n" );
|
||||
});
|
||||
|
||||
c.addListener("data", function (chunk) {
|
||||
// console.log(chunk);
|
||||
res_buffer += chunk;
|
||||
});
|
||||
|
||||
c.addListener("end", function () {
|
||||
c.end();
|
||||
assert.ok(! /x-foo/.test(res_buffer), "Trailer in HTTP/1.0 response.");
|
||||
outstanding_reqs--;
|
||||
if (outstanding_reqs == 0) {
|
||||
server.close();
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// now, we test an HTTP/1.1 request.
|
||||
server.addListener("listening", function() {
|
||||
var c = net.createConnection(common.PORT);
|
||||
var res_buffer = "";
|
||||
var tid;
|
||||
|
||||
c.setEncoding("utf8");
|
||||
|
||||
c.addListener("connect", function () {
|
||||
outstanding_reqs++;
|
||||
c.write( "GET / HTTP/1.1\r\n\r\n" );
|
||||
tid = setTimeout(assert.fail, 2000, "Couldn't find last chunk.");
|
||||
});
|
||||
|
||||
c.addListener("data", function (chunk) {
|
||||
// console.log(chunk);
|
||||
res_buffer += chunk;
|
||||
if (/0\r\n/.test(res_buffer)) { // got the end.
|
||||
outstanding_reqs--;
|
||||
clearTimeout(tid);
|
||||
assert.ok(
|
||||
/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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue