From b27f8ba06d6c965056f9539660fb8704c6ca37f5 Mon Sep 17 00:00:00 2001 From: Ryan Date: Fri, 31 Jul 2009 18:34:27 +0200 Subject: [PATCH] Default to chunked for client requests without C-Length. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also add test. Reported by Felix Geisendörfer. --- src/http.js | 40 ++++++++++--------- test/mjsunit/test-http-client-upload.js | 52 +++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 test/mjsunit/test-http-client-upload.js diff --git a/src/http.js b/src/http.js index adf4ac9d1d..94430c1496 100644 --- a/src/http.js +++ b/src/http.js @@ -140,10 +140,6 @@ function OutgoingMessage () { this.output = []; - this.sent_connection_header = false; - this.sent_content_length_header = false; - this.sent_transfer_encoding_header = false; - this.closeOnFinish = false; this.chunked_encoding = false; this.should_keep_alive = true; @@ -159,6 +155,10 @@ OutgoingMessage.prototype.send = function (data, encoding) { }; 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 || []; // 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; if (connection_expression.exec(field)) { - this.sent_connection_header = true; + sent_connection_header = true; if (close_expression.exec(value)) this.closeOnFinish = true; } 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; } else if (content_length_expression.exec(field)) { - this.sent_content_length_header = true; + sent_content_length_header = true; } } // keep-alive logic - if (this.sent_connection_header == false) { + if (sent_connection_header == false) { if (this.should_keep_alive) { header += "Connection: keep-alive\r\n"; } 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) { header += "Transfer-Encoding: chunked\r\n"; this.chunked_encoding = true; @@ -251,7 +251,11 @@ function ClientRequest (method, uri, header_lines) { OutgoingMessage.call(this); 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.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 * should be closed. */ function flushMessageQueue (connection, queue) { - if (connection.readyState === "closed" || connection.readyState === "readOnly") { + if (connection.readyState !== "open" && connection.readyState !== "writeOnly") { 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) { var req = incoming; var res = new ServerResponse(connection); res.should_keep_alive = should_keep_alive; - res.addListener("flush", flushResponse); + res.addListener("flush", function () { + if(flushMessageQueue(connection, responses)) { + connection.fullClose(); + } + }); responses.push(res); connection.server.emit("request", [req, res]); @@ -405,6 +408,7 @@ node.http.createClient = function (port, host) { client.connect(port, host); // reconnect return; } + //node.debug("client flush readyState = " + client.readyState); if (req == requests[0]) flushMessageQueue(client, [req]); }); requests.push(req); @@ -437,7 +441,7 @@ node.http.createClient = function (port, host) { }); createIncomingMessageStream(client, function (res) { - //node.debug("incoming response!"); + //node.debug("incoming response!"); res.addListener("complete", function ( ) { //node.debug("request complete disconnecting. readyState = " + client.readyState); diff --git a/test/mjsunit/test-http-client-upload.js b/test/mjsunit/test-http-client-upload.js new file mode 100644 index 0000000000..e5ad377d2b --- /dev/null +++ b/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); +}