From 6a172d71199524af0fc3e5b75729b855502e25c9 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 19 May 2009 20:24:37 +0200 Subject: [PATCH] Fix a bug in HTTP server when receiving half-closes. --- src/http.js | 30 +++++++++++++++++------------- src/net.cc | 2 +- test/test-http.js | 25 ++++++++++++++++++------- test/test-pingpong.js | 17 ++++++++++++++--- test_client.js | 23 ++++++++++++++++++++--- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/http.js b/src/http.js index a2642cc3d92..5934bebdb63 100644 --- a/src/http.js +++ b/src/http.js @@ -105,6 +105,7 @@ function toRaw(string) { node.http.ServerResponse = function (connection, responses) { responses.push(this); this.connection = connection; + this.closeOnFinish = false; var output = []; // The send method appends data onto the output array. The deal is, @@ -151,14 +152,7 @@ node.http.ServerResponse = function (connection, responses) { output.push(data); }; - this.flush = function () { - if (responses.length > 0 && responses[0] === this) - while (output.length > 0) - connection.send(output.shift()); - }; - var chunked_encoding = false; - var connection_close = false; this.sendHeader = function (status_code, headers) { var sent_connection_header = false; @@ -225,6 +219,14 @@ node.http.ServerResponse = function (connection, responses) { this.flush(); }; + this.flush = function () { + if (responses.length > 0 && responses[0] === this) + while (output.length > 0) { + var out = output.shift(); + connection.send(out); + } + }; + this.finished = false; this.finish = function () { if (chunked_encoding) @@ -235,12 +237,10 @@ node.http.ServerResponse = function (connection, responses) { while (responses.length > 0 && responses[0].finished) { var res = responses[0]; res.flush(); + if (res.closeOnFinish) + connection.fullClose(); responses.shift(); } - - if (responses.length == 0 && connection_close) { - connection.fullClose(); - } }; }; @@ -322,7 +322,11 @@ node.http.Server = function (RequestHandler, options) { // is this really needed? connection.onEOF = function () { - connection.close(); + puts("HTTP SERVER got eof"); + if (responses.length == 0) + connection.close(); + else + responses[responses.length-1].closeOnFinish = true; }; } @@ -355,7 +359,7 @@ node.http.Client = function (port, host) { if (connection_expression.exec(field)) { sent_connection_header = true; if (close_expression.exec(value)) - connection_close = true; + this.closeOnFinish = true; } else if (transfer_encoding_expression.exec(field)) { sent_transfer_encoding_header = true; if (chunk_expression.exec(value)) diff --git a/src/net.cc b/src/net.cc index 5fd2f494aa6..fbed1afebb9 100644 --- a/src/net.cc +++ b/src/net.cc @@ -440,7 +440,7 @@ void name () \ TryCatch try_catch; \ callback->Call(handle_, 0, NULL); \ if (try_catch.HasCaught()) \ - fatal_exception(try_catch); \ + node::fatal_exception(try_catch); \ } DEFINE_SIMPLE_CALLBACK(Connection::OnConnect, ON_CONNECT_SYMBOL) diff --git a/test/test-http.js b/test/test-http.js index 13e52a0364f..c8e05bb8cb6 100644 --- a/test/test-http.js +++ b/test/test-http.js @@ -7,24 +7,26 @@ function onLoad() { var request_number = 0; new node.http.Server(function (req, res) { - var server = this; + res.id = request_number; req.id = request_number++; + if (req.id == 0) { - puts("get req"); + //puts("get req"); assertEquals("GET", req.method); assertEquals("/hello", req.uri.path); } if (req.id == 1) { - puts("post req"); + //puts("post req"); assertEquals("POST", req.method); assertEquals("/quit", req.uri.path); - server.close(); - puts("server closed"); + this.close(); + //puts("server closed"); } setTimeout(function () { + //puts("send response"); res.sendHeader(200, [["Content-Type", "text/plain"]]); res.sendBody(req.uri.path); res.finish(); @@ -35,13 +37,14 @@ function onLoad() { var c = new node.tcp.Connection(); var req_sent = 0; c.onConnect = function () { - puts("send get"); + //puts("send get"); c.send( "GET /hello HTTP/1.1\r\n\r\n" ); req_sent += 1; }; var total = ""; c.onReceive = function (chunk) { + //puts("client recv"); total += chunk.encodeUtf8(); puts("total: " + JSON.stringify(total)); @@ -49,12 +52,20 @@ function onLoad() { puts("send post"); c.send("POST /quit HTTP/1.1\r\n\r\n"); c.close(); + puts("client half close"); + assertEquals(c.readyState, "readOnly"); req_sent += 1; } }; + c.onEOF = function () { + puts("client got eof"); + }; + c.onDisconnect = function () { - puts("client disocnnected"); + puts("client disconnected"); + + assertEquals(c.readyState, "closed"); var hello = new RegExp("/hello"); assertTrue(hello.exec(total) != null); diff --git a/test/test-pingpong.js b/test/test-pingpong.js index 79cc84c0d28..5395b590c31 100644 --- a/test/test-pingpong.js +++ b/test/test-pingpong.js @@ -48,23 +48,34 @@ function onLoad() { client.send("PING"); }; + var sent_final_ping = false; + client.onReceive = function (data) { - assertEquals("open", client.readyState); //puts("client recved data: " + JSON.stringify(data)); stdout.print("."); assertEquals("PONG", data); count += 1; + + if (sent_final_ping) { + assertEquals("readOnly", client.readyState); + return; + } else { + assertEquals("open", client.readyState); + } + if (count < N) { client.send("PING"); } else { - puts("sending FIN"); + puts("sending final ping"); + sent_final_ping = true; + client.send("PING"); client.close(); } }; client.onEOF = function () { puts("pinger: onEOF"); - assertEquals(N, count); + assertEquals(N+1, count); }; client.connect(port); diff --git a/test_client.js b/test_client.js index 8e37f680286..56fe6acf944 100644 --- a/test_client.js +++ b/test_client.js @@ -2,15 +2,32 @@ var c = new node.http.Client(8000, "localhost") var req = c.get("/hello/world", [["Accept", "*/*"]]); req.finish(function (res) { - puts("got response: " + res.status_code.toString()); + puts("response 1: " + res.status_code.toString()); res.onBody = function (chunk) { - puts("got response body <" + chunk.encodeUtf8() + ">"); + puts("response 1 body <" + chunk.encodeUtf8() + ">"); return true; }; res.onBodyComplete = function () { - puts("response complete!"); + puts("response 1 complete!"); return true; }; }); + +/* +var req = c.get("/something/else", []); +req.finish(function (res) { + puts("response 2: " + res.status_code.toString()); + + res.onBody = function (chunk) { + puts("response 2 body <" + chunk.encodeUtf8() + ">"); + return true; + }; + + res.onBodyComplete = function () { + puts("response 2 complete!"); + return true; + }; +}); +*/