Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions src/js/node/http2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5331,6 +5331,8 @@ function createHttp1FallbackResponseHandle(socket, shouldKeepAlive, keepAliveTim
let head = null;
let headWritten = false;
let chunked = false;
let noBody = false;
let closeDelimited = false;

function writeHeadToSocket(contentLength) {
if (headWritten) return;
Expand All @@ -5343,41 +5345,46 @@ function createHttp1FallbackResponseHandle(socket, shouldKeepAlive, keepAliveTim
let out = `HTTP/1.1 ${statusCode} ${statusMessage}\r\n`;
let hasContentLength = false;
let hasTransferEncoding = false;
let hasDate = false;
let hasConnection = false;
// renderNativeHeaders() (see _http_server.ts) hands the native handle a
// flat [name, value, name, value, ...] array, not an array of pairs, so
// the values are read two entries at a time. A NUL-named sentinel pair
// carries a framing decision rather than a real header: value "2" means no
// body (HEAD), value "1" means the body is close-delimited.
const headers = head?.headers;
if (headers) {
for (const { 0: name, 1: value } of headers) {
switch (name) {
for (let i = 0; i + 1 < headers.length; i += 2) {
const name = headers[i];
const value = headers[i + 1];
if (name === "\u0000") {
if (value === "2") noBody = true;
else closeDelimited = true;
continue;
}
switch (name.toLowerCase()) {
case "content-length":
hasContentLength = true;
break;
case "transfer-encoding":
hasTransferEncoding = true;
if (String(value).toLowerCase().includes("chunked")) chunked = true;
break;
case "date":
hasDate = true;
break;
case "connection":
hasConnection = true;
break;
}
out += `${name}: ${value}\r\n`;
}
}
if (!hasContentLength && !hasTransferEncoding) {
if (!noBody && !closeDelimited && !hasContentLength && !hasTransferEncoding) {
if (contentLength === null) {
chunked = true;
out += "Transfer-Encoding: chunked\r\n";
} else {
out += `Content-Length: ${contentLength}\r\n`;
}
}
if (!hasDate) {
// renderNativeHeaders() is the source of truth for the Date and Connection
// response headers (it honors res.sendDate and res.removeHeader("connection")),
// so only synthesize them when no rendered header array was provided.
if (!headers) {
out += `Date: ${new Date().toUTCString()}\r\n`;
}
if (!hasConnection) {
if (shouldKeepAlive) {
out += `Connection: keep-alive\r\nKeep-Alive: timeout=${Math.floor((keepAliveTimeout || 5000) / 1000)}\r\n`;
} else {
Comment thread
robobun marked this conversation as resolved.
Expand Down Expand Up @@ -5428,17 +5435,23 @@ function createHttp1FallbackResponseHandle(socket, shouldKeepAlive, keepAliveTim
write(chunk, encoding, _callback, _strictContentLength) {
const buf = toBuffer(chunk, encoding);
writeHeadToSocket(null);
if (noBody) return 0;
return writeBody(buf);
},
end(chunk, encoding, _callback, _strictContentLength) {
if (this.ended) return 0;
const buf = toBuffer(chunk, encoding);
const length = buf ? (buf.byteLength ?? buf.length) : 0;
writeHeadToSocket(length);
writeBody(buf);
if (chunked) socket.write("0\r\n\r\n");
if (!noBody) {
writeBody(buf);
if (chunked) socket.write("0\r\n\r\n");
}
this.ended = true;
this.finished = true;
if (closeDelimited && !socket.destroyed) {
socket.end();
}
const onfinished = this.onfinished;
if (onfinished) {
this.onfinished = null;
Expand Down Expand Up @@ -5524,6 +5537,9 @@ function connectionListenerHTTP1(server, socket, options) {
};

const res = new ServerResponseClass(req);
// Mirror the native node:http path (_http_server.ts) so renderNativeHeaders()
// emits the Keep-Alive: timeout header on persistent connections.
res._keepAliveTimeout = keepAliveTimeout;
const handle = createHttp1FallbackResponseHandle(socket, shouldKeepAlive, keepAliveTimeout);
handle.onfinished = function () {
socket[kHttp1ActiveRequests] = Math.max(0, (socket[kHttp1ActiveRequests] || 1) - 1);
Expand Down
Loading
Loading