From b47c44d7a660d9ee6ab365864e345081f237b433 Mon Sep 17 00:00:00 2001 From: koichik Date: Wed, 4 Jan 2012 19:05:41 +0100 Subject: [PATCH] Fix response body is not read With HTTP/1.1, if neither Content-Length nor Transfer-Encoding is present, section 4.4 of RFC 2616 suggests http-parser needs to read a response body until the connection is closed (except the response must not include a body) See also joyent/node#2457. Fixes #72 --- http_parser.c | 15 +++++++++++++-- test.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/http_parser.c b/http_parser.c index bbeceb0..5e135f7 100644 --- a/http_parser.c +++ b/http_parser.c @@ -1733,9 +1733,20 @@ http_should_keep_alive (http_parser *parser) /* HTTP/1.1 */ if (parser->flags & F_CONNECTION_CLOSE) { return 0; - } else { - return 1; } + if (parser->type == HTTP_RESPONSE) { + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + parser->flags & F_SKIPBODY) { /* response to a HEAD request */ + return 1; + } + if (!(parser->flags & F_CHUNKED) && parser->content_length == -1) { + return 0; + } + } + return 1; } else { /* HTTP/1.0 or earlier */ if (parser->flags & F_CONNECTION_KEEP_ALIVE) { diff --git a/test.c b/test.c index 6af0e78..be633eb 100644 --- a/test.c +++ b/test.c @@ -780,8 +780,8 @@ const struct message responses[] = , {.name= "404 no headers no body" ,.type= HTTP_RESPONSE ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE ,.http_major= 1 ,.http_minor= 1 ,.status_code= 404 @@ -795,8 +795,8 @@ const struct message responses[] = , {.name= "301 no response phrase" ,.type= HTTP_RESPONSE ,.raw= "HTTP/1.1 301\r\n\r\n" - ,.should_keep_alive = TRUE - ,.message_complete_on_eof= FALSE + ,.should_keep_alive = FALSE + ,.message_complete_on_eof= TRUE ,.http_major= 1 ,.http_minor= 1 ,.status_code= 301 @@ -1057,8 +1057,46 @@ const struct message responses[] = {} ,.body= "" } -, {.name= NULL } /* sentinel */ +#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 13 +/* The client should wait for the server's EOF. That is, when neither + * content-length nor transfer-encoding is specified, the end of body + * is specified by the EOF. + */ +, {.name= "neither content-length nor transfer-encoding response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 1 + ,.headers= + { { "Content-Type", "text/plain" } + } + ,.body= "hello world" + } + +#define NO_HEADERS_NO_BODY_204 14 +, {.name= "204 no headers no body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No Content\r\n\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.num_headers= 0 + ,.headers= {} + ,.body_size= 0 + ,.body= "" + } + +, {.name= NULL } /* sentinel */ }; int @@ -1888,7 +1926,7 @@ main (void) printf("response scan 1/2 "); test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY] - , &responses[NO_HEADERS_NO_BODY_404] + , &responses[NO_HEADERS_NO_BODY_204] , &responses[NO_REASON_PHRASE] );