Simplify state transitions in http.Client
Fixes new bug shown in test-http-allow-req-after-204-res.js pointed out by Tom Carden <tom.carden@gmail.com>.
This commit is contained in:
parent
85827bde34
commit
735b9d50a3
32
lib/http.js
32
lib/http.js
@ -880,6 +880,12 @@ function Client ( ) {
|
|||||||
net.Stream.call(this, { allowHalfOpen: true });
|
net.Stream.call(this, { allowHalfOpen: true });
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
// Possible states:
|
||||||
|
// - disconnected
|
||||||
|
// - connecting
|
||||||
|
// - connected
|
||||||
|
this._state = 'disconnected';
|
||||||
|
|
||||||
httpSocketSetup(self);
|
httpSocketSetup(self);
|
||||||
|
|
||||||
function onData(d, start, end) {
|
function onData(d, start, end) {
|
||||||
@ -912,6 +918,8 @@ function Client ( ) {
|
|||||||
self.ondata = onData;
|
self.ondata = onData;
|
||||||
self.onend = onEnd;
|
self.onend = onEnd;
|
||||||
|
|
||||||
|
self._state = "connected";
|
||||||
|
|
||||||
self._initParser();
|
self._initParser();
|
||||||
debug('CLIENT requests: ' + util.inspect(self._outgoing.map(function (r) { return r.method; })));
|
debug('CLIENT requests: ' + util.inspect(self._outgoing.map(function (r) { return r.method; })));
|
||||||
outgoingFlush(self);
|
outgoingFlush(self);
|
||||||
@ -919,21 +927,22 @@ function Client ( ) {
|
|||||||
|
|
||||||
function onEnd() {
|
function onEnd() {
|
||||||
if (self.parser) self.parser.finish();
|
if (self.parser) self.parser.finish();
|
||||||
debug("CLIENT got end closing. readyState = " + self.readyState);
|
debug("CLIENT got end closing. state = " + self._state);
|
||||||
self.end();
|
self.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
self.addListener("close", function (e) {
|
self.addListener("close", function (e) {
|
||||||
|
self._state = "disconnected";
|
||||||
if (e) return;
|
if (e) return;
|
||||||
|
|
||||||
debug("CLIENT onClose. readyState = " + self.readyState);
|
debug("CLIENT onClose. state = " + self._state);
|
||||||
|
|
||||||
// finally done with the request
|
// finally done with the request
|
||||||
self._outgoing.shift();
|
self._outgoing.shift();
|
||||||
|
|
||||||
// If there are more requests to handle, reconnect.
|
// If there are more requests to handle, reconnect.
|
||||||
if (self._outgoing.length) {
|
if (self._outgoing.length) {
|
||||||
self._reconnect();
|
self._ensureConnection();
|
||||||
} else if (self.parser) {
|
} else if (self.parser) {
|
||||||
parsers.free(self.parser);
|
parsers.free(self.parser);
|
||||||
self.parser = null;
|
self.parser = null;
|
||||||
@ -982,7 +991,7 @@ Client.prototype._initParser = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.addListener('end', function ( ) {
|
res.addListener('end', function ( ) {
|
||||||
debug("CLIENT request complete disconnecting. readyState = " + self.readyState);
|
debug("CLIENT request complete disconnecting. state = " + self._state);
|
||||||
// For the moment we reconnect for every request. FIXME!
|
// For the moment we reconnect for every request. FIXME!
|
||||||
// All that should be required for keep-alive is to not reconnect,
|
// All that should be required for keep-alive is to not reconnect,
|
||||||
// but outgoingFlush instead.
|
// but outgoingFlush instead.
|
||||||
@ -1020,17 +1029,18 @@ Client.prototype._onOutgoingSent = function (message) {
|
|||||||
//
|
//
|
||||||
// Instead, we just check if the connection is closed, and if so
|
// Instead, we just check if the connection is closed, and if so
|
||||||
// reconnect if we have pending messages.
|
// reconnect if we have pending messages.
|
||||||
if (this._outgoing.length && this.readyState == "closed") {
|
if (this._outgoing.length) {
|
||||||
debug("CLIENT request flush. reconnect. readyState = " + this.readyState);
|
debug("CLIENT request flush. ensure connection. state = " + this._state);
|
||||||
this._reconnect();
|
this._ensureConnection();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Client.prototype._reconnect = function () {
|
Client.prototype._ensureConnection = function () {
|
||||||
if (this.readyState === "closed") {
|
if (this._state == 'disconnected') {
|
||||||
debug("CLIENT reconnecting readyState = " + this.readyState);
|
debug("CLIENT reconnecting state = " + this._state);
|
||||||
this.connect(this.port, this.host);
|
this.connect(this.port, this.host);
|
||||||
|
this._state = "connecting";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1044,7 +1054,7 @@ Client.prototype.request = function (method, url, headers) {
|
|||||||
}
|
}
|
||||||
var req = new ClientRequest(this, method, url, headers);
|
var req = new ClientRequest(this, method, url, headers);
|
||||||
this._outgoing.push(req);
|
this._outgoing.push(req);
|
||||||
if (this.readyState === 'closed') this._reconnect();
|
this._ensureConnection();
|
||||||
return req;
|
return req;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
43
test/simple/test-http-allow-req-after-204-res.js
Normal file
43
test/simple/test-http-allow-req-after-204-res.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
var common = require('../common');
|
||||||
|
var http = require('http');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
// first 204 or 304 works, subsequent anything fails
|
||||||
|
var codes = [ 204, 200 ];
|
||||||
|
|
||||||
|
// Methods don't really matter, but we put in something realistic.
|
||||||
|
var methods = ['DELETE', 'DELETE'];
|
||||||
|
|
||||||
|
var server = http.createServer(function (req, res) {
|
||||||
|
var code = codes.shift();
|
||||||
|
assert.equal('number', typeof code);
|
||||||
|
assert.ok(code > 0);
|
||||||
|
console.error('writing %d response', code);
|
||||||
|
res.writeHead(code, {});
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
var client = http.createClient(common.PORT);
|
||||||
|
|
||||||
|
function nextRequest() {
|
||||||
|
var method = methods.shift();
|
||||||
|
console.error("writing request: %s", method);
|
||||||
|
|
||||||
|
var request = client.request(method, '/');
|
||||||
|
request.on('response', function (response) {
|
||||||
|
response.on('end', function() {
|
||||||
|
if (methods.length == 0) {
|
||||||
|
console.error("close server");
|
||||||
|
server.close();
|
||||||
|
} else {
|
||||||
|
// throws error:
|
||||||
|
nextRequest();
|
||||||
|
// works just fine:
|
||||||
|
//process.nextTick(nextRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
request.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
server.listen(common.PORT, nextRequest);
|
Loading…
x
Reference in New Issue
Block a user