No keepAliveTimeout for HTTP server after answering a POST request synchronously
Personne n'a encore pris cette issue.
- Langage dominant
- JavaScript
- Étoiles
- 122k
- Forks
- 37.3k
- Merge moyen
- 4 j 2 h
- PR mergées (30 j)
- 283
Description
- Version: v16.4.0
- Platform: Linux test01 4.19.0-13-amd64 # 1 SMP Debian 4.19.160-2 (2020-11-28) x86_64 GNU/Linux
- Subsystem: http
What steps will reproduce the bug?
When using the "normal" NodeJS "hello world" HTTP server example, which answers any request synchronously, and sending it a POST request with a body, server.keepAliveTimeout (default 5 sec) does not work. The HTTP connection remains open ("forever"?).
Complete Testcase
Here we test all 4 combinations of sync/async response and get/post request to a simple HTTP server, and expect a connection close from server after 1 sec - which works fine for all combinations except "synchronous response for a POST request". If the connection is still open, we try another request - to prove, the connection still works:
'use strict';
const http = require('http');
const net = require('net');
const server = http.createServer((req, res) => {
if (req.url === '/async') {
req.on('data', () => {});
req.on('end', () => {
res.end('test-body');
console.log('Server: Sent response asynchronously');
});
} else {
res.end('test-body');
console.log('Server: Sent response synchronously');
}
});
server.keepAliveTimeout = 1000;
server.listen(0, async () => {
await sendRequests('async', 'get');
await sendRequests('async', 'post');
await sendRequests('sync', 'get');
await sendRequests('sync', 'post'); // keepAliveTimeout does not work here!!
server.close();
});
async function sendRequests(type, method) {
console.log(`=== Testing ${type} response for method "${method}" and wait for keep-alive-close`);
return new Promise((resolve) => {
const client = new net.Socket();
let nextReqTimeout = null;
client.connect(server.address().port, '127.0.0.1', () => {
console.log('Client: Connected to server');
httpRequest();
nextReqTimeout = setTimeout(() => {
console.log('Client: ERROR: HTTP-Connection is still open - trying another request');
httpRequest();
nextReqTimeout = setTimeout(() => {
console.log('Client: ERROR: HTTP-Connection is still open - closing from client side now');
nextReqTimeout = null;
client.end();
}, server.keepAliveTimeout * 2);
}, server.keepAliveTimeout * 2);
});
client.on('data', function(data) {
console.log('Client: Got response data');
});
client.on('close', function() {
if (nextReqTimeout) {
console.log('Client: Server closed connection as expected');
clearTimeout(nextReqTimeout);
}
resolve();
});
function httpRequest() {
const rawRequests = {
'post': 'POST /' + type + ' HTTP/1.1\r\n' +
'Connection: keep-alive\r\n' +
'Content-Type: application/x-www-form-urlencoded\r\n' +
'Content-Length: 10\r\n' +
'\r\n' +
'Test=67890',
'get': 'GET /' + type + ' HTTP/1.1\r\n' +
'Connection: keep-alive\r\n' +
'\r\n'
};
console.log('Client: Sending request');
client.write(rawRequests[method]);
}
});
}
What is the expected behavior?
The keepAliveTimeout should also work after answering a POST request synchronously.
Possible cause
Maybe this is a race condition here:
- In
resOnFinishtheserver.keepAliveTimeoutis set on the socket, after sending the response - After that,
socketOnDatais called internally for the remaining POST body, which callsonParserExecuteCommon, which resets the socket timeout first - Normally
socketOnDatais called before sending the response, so in most cases it works as expected
Maybe there should be a swicth, to not reset the socket-timeout when socketOnData is called after the response was sent?
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Exécutez d’abord la reproduction JavaScript fournie, puis lisez dans lib/_http_server.js autour de resOnFinish, socketOnData et onParserExecuteCommon. Suivez la façon dont le corps POST restant réinitialise le délai d’expiration du socket après la réponse synchrone. C’est terminé lorsque le cas POST synchrone se ferme après server.keepAliveTimeout comme les trois autres cas, avec une couverture de régression pour le comportement signalé.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- javascript
- Domaine
- api, backend
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Active
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 68/100