Browse Source

Default to chunked for client requests without C-Length.

Also add test. Reported by Felix Geisendörfer.
v0.7.4-release
Ryan 16 years ago
parent
commit
b27f8ba06d
  1. 40
      src/http.js
  2. 52
      test/mjsunit/test-http-client-upload.js

40
src/http.js

@ -140,10 +140,6 @@ function OutgoingMessage () {
this.output = []; this.output = [];
this.sent_connection_header = false;
this.sent_content_length_header = false;
this.sent_transfer_encoding_header = false;
this.closeOnFinish = false; this.closeOnFinish = false;
this.chunked_encoding = false; this.chunked_encoding = false;
this.should_keep_alive = true; this.should_keep_alive = true;
@ -159,6 +155,10 @@ OutgoingMessage.prototype.send = function (data, encoding) {
}; };
OutgoingMessage.prototype.sendHeaderLines = function (first_line, header_lines) { OutgoingMessage.prototype.sendHeaderLines = function (first_line, header_lines) {
var sent_connection_header = false;
var sent_content_length_header = false;
var sent_transfer_encoding_header = false;
header_lines = header_lines || []; header_lines = header_lines || [];
// first_line in the case of request is: "GET /index.html HTTP/1.1\r\n" // first_line in the case of request is: "GET /index.html HTTP/1.1\r\n"
@ -172,21 +172,21 @@ OutgoingMessage.prototype.sendHeaderLines = function (first_line, header_lines)
header += field + ": " + value + CRLF; header += field + ": " + value + CRLF;
if (connection_expression.exec(field)) { if (connection_expression.exec(field)) {
this.sent_connection_header = true; sent_connection_header = true;
if (close_expression.exec(value)) this.closeOnFinish = true; if (close_expression.exec(value)) this.closeOnFinish = true;
} else if (transfer_encoding_expression.exec(field)) { } else if (transfer_encoding_expression.exec(field)) {
this.sent_transfer_encoding_header = true; sent_transfer_encoding_header = true;
if (chunk_expression.exec(value)) this.chunked_encoding = true; if (chunk_expression.exec(value)) this.chunked_encoding = true;
} else if (content_length_expression.exec(field)) { } else if (content_length_expression.exec(field)) {
this.sent_content_length_header = true; sent_content_length_header = true;
} }
} }
// keep-alive logic // keep-alive logic
if (this.sent_connection_header == false) { if (sent_connection_header == false) {
if (this.should_keep_alive) { if (this.should_keep_alive) {
header += "Connection: keep-alive\r\n"; header += "Connection: keep-alive\r\n";
} else { } else {
@ -195,7 +195,7 @@ OutgoingMessage.prototype.sendHeaderLines = function (first_line, header_lines)
} }
} }
if (this.sent_content_length_header == false && this.sent_transfer_encoding_header == false) { if (sent_content_length_header == false && sent_transfer_encoding_header == false) {
if (this.use_chunked_encoding_by_default) { if (this.use_chunked_encoding_by_default) {
header += "Transfer-Encoding: chunked\r\n"; header += "Transfer-Encoding: chunked\r\n";
this.chunked_encoding = true; this.chunked_encoding = true;
@ -251,7 +251,11 @@ function ClientRequest (method, uri, header_lines) {
OutgoingMessage.call(this); OutgoingMessage.call(this);
this.should_keep_alive = false; this.should_keep_alive = false;
this.use_chunked_encoding_by_default = false; if (method === "GET" || method === "HEAD") {
this.use_chunked_encoding_by_default = false;
} else {
this.use_chunked_encoding_by_default = true;
}
this.closeOnFinish = true; this.closeOnFinish = true;
this.sendHeaderLines(method + " " + uri + " HTTP/1.1\r\n", header_lines); this.sendHeaderLines(method + " " + uri + " HTTP/1.1\r\n", header_lines);
@ -329,7 +333,7 @@ function createIncomingMessageStream (connection, incoming_listener) {
/* Returns true if the message queue is finished and the connection /* Returns true if the message queue is finished and the connection
* should be closed. */ * should be closed. */
function flushMessageQueue (connection, queue) { function flushMessageQueue (connection, queue) {
if (connection.readyState === "closed" || connection.readyState === "readOnly") { if (connection.readyState !== "open" && connection.readyState !== "writeOnly") {
return false; return false;
} }
@ -374,18 +378,17 @@ function connectionListener (connection) {
} }
}); });
var flushResponse = function () {
if(flushMessageQueue(connection, responses)) {
connection.fullClose();
}
};
createIncomingMessageStream(connection, function (incoming, should_keep_alive) { createIncomingMessageStream(connection, function (incoming, should_keep_alive) {
var req = incoming; var req = incoming;
var res = new ServerResponse(connection); var res = new ServerResponse(connection);
res.should_keep_alive = should_keep_alive; res.should_keep_alive = should_keep_alive;
res.addListener("flush", flushResponse); res.addListener("flush", function () {
if(flushMessageQueue(connection, responses)) {
connection.fullClose();
}
});
responses.push(res); responses.push(res);
connection.server.emit("request", [req, res]); connection.server.emit("request", [req, res]);
@ -405,6 +408,7 @@ node.http.createClient = function (port, host) {
client.connect(port, host); // reconnect client.connect(port, host); // reconnect
return; return;
} }
//node.debug("client flush readyState = " + client.readyState);
if (req == requests[0]) flushMessageQueue(client, [req]); if (req == requests[0]) flushMessageQueue(client, [req]);
}); });
requests.push(req); requests.push(req);
@ -437,7 +441,7 @@ node.http.createClient = function (port, host) {
}); });
createIncomingMessageStream(client, function (res) { createIncomingMessageStream(client, function (res) {
//node.debug("incoming response!"); //node.debug("incoming response!");
res.addListener("complete", function ( ) { res.addListener("complete", function ( ) {
//node.debug("request complete disconnecting. readyState = " + client.readyState); //node.debug("request complete disconnecting. readyState = " + client.readyState);

52
test/mjsunit/test-http-client-upload.js

@ -0,0 +1,52 @@
include("mjsunit.js");
var PORT = 18032;
var sent_body = "";
var server_req_complete = false;
var client_res_complete = false;
var server = node.http.createServer(function(req, res) {
assertEquals("POST", req.method);
req.setBodyEncoding("utf8");
req.addListener("body", function (chunk) {
puts("server got: " + JSON.stringify(chunk));
sent_body += chunk;
});
req.addListener("complete", function () {
server_req_complete = true;
puts("request complete from server");
res.sendHeader(200, [['Content-Type', 'text/plain']]);
res.sendBody('hello\n');
res.finish();
});
});
server.listen(PORT);
function onLoad () {
var client = node.http.createClient(PORT);
var req = client.post('/');
req.sendBody('1\n');
req.sendBody('2\n');
req.sendBody('3\n');
puts("client finished sending request");
req.finish(function(res) {
res.setBodyEncoding("utf8");
res.addListener('body', function(chunk) {
puts(chunk);
});
res.addListener('complete', function() {
client_res_complete = true;
server.close();
});
});
}
function onExit () {
assertEquals("1\n2\n3\n", sent_body);
assertTrue(server_req_complete);
assertTrue(client_res_complete);
}
Loading…
Cancel
Save