http: fix no dumping after maybeReadMore
When `maybeReadMore` kicks in on a first bytes of incoming data, the `req.read(0)` will be invoked and the `req._consuming` will be set to `true`. This seemingly harmless property leads to a dire consequences: the server won't call `req._dump()` and the whole HTTP/1.1 pipeline will hang (single connection). PR-URL: https://github.com/nodejs/node/pull/7211 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
1a1ff77feb
commit
357f904169
@ -20,6 +20,13 @@ exports.readStop = readStop;
|
|||||||
function IncomingMessage(socket) {
|
function IncomingMessage(socket) {
|
||||||
Stream.Readable.call(this);
|
Stream.Readable.call(this);
|
||||||
|
|
||||||
|
// Set this to `true` so that stream.Readable won't attempt to read more
|
||||||
|
// data on `IncomingMessage#push` (see `maybeReadMore` in
|
||||||
|
// `_stream_readable.js`). This is important for proper tracking of
|
||||||
|
// `IncomingMessage#_consuming` which is used to dump requests that users
|
||||||
|
// haven't attempted to read.
|
||||||
|
this._readableState.readingMore = true;
|
||||||
|
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.connection = socket;
|
this.connection = socket;
|
||||||
|
|
||||||
@ -67,6 +74,8 @@ IncomingMessage.prototype.setTimeout = function(msecs, callback) {
|
|||||||
|
|
||||||
|
|
||||||
IncomingMessage.prototype.read = function(n) {
|
IncomingMessage.prototype.read = function(n) {
|
||||||
|
if (!this._consuming)
|
||||||
|
this._readableState.readingMore = false;
|
||||||
this._consuming = true;
|
this._consuming = true;
|
||||||
this.read = Stream.Readable.prototype.read;
|
this.read = Stream.Readable.prototype.read;
|
||||||
return this.read(n);
|
return this.read(n);
|
||||||
|
51
test/parallel/test-http-no-read-no-dump.js
Normal file
51
test/parallel/test-http-no-read-no-dump.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
let onPause = null;
|
||||||
|
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
|
if (req.method === 'GET')
|
||||||
|
return res.end();
|
||||||
|
|
||||||
|
res.writeHead(200);
|
||||||
|
res.flushHeaders();
|
||||||
|
|
||||||
|
req.connection.on('pause', () => {
|
||||||
|
res.end();
|
||||||
|
onPause();
|
||||||
|
});
|
||||||
|
}).listen(common.PORT, common.mustCall(() => {
|
||||||
|
const agent = new http.Agent({
|
||||||
|
maxSockets: 1,
|
||||||
|
keepAlive: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const post = http.request({
|
||||||
|
agent: agent,
|
||||||
|
method: 'POST',
|
||||||
|
port: common.PORT,
|
||||||
|
}, common.mustCall((res) => {
|
||||||
|
res.resume();
|
||||||
|
|
||||||
|
post.write(Buffer.alloc(16 * 1024).fill('X'));
|
||||||
|
onPause = () => {
|
||||||
|
post.end('something');
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
/* What happens here is that the server `end`s the response before we send
|
||||||
|
* `something`, and the client thought that this is a green light for sending
|
||||||
|
* next GET request
|
||||||
|
*/
|
||||||
|
post.write('initial');
|
||||||
|
|
||||||
|
http.request({
|
||||||
|
agent: agent,
|
||||||
|
method: 'GET',
|
||||||
|
port: common.PORT,
|
||||||
|
}, common.mustCall((res) => {
|
||||||
|
server.close();
|
||||||
|
res.connection.end();
|
||||||
|
})).end();
|
||||||
|
}));
|
Loading…
x
Reference in New Issue
Block a user