mirror of
https://github.com/nodejs/http-parser.git
synced 2025-10-21 07:02:06 +08:00
Bug Fix: Connection:close with missing Content-Length.
The test and bug report are from tomika.
This commit is contained in:
@@ -96,7 +96,7 @@ struct http_parser {
|
|||||||
unsigned short method; /* requests only */
|
unsigned short method; /* requests only */
|
||||||
short version;
|
short version;
|
||||||
short keep_alive;
|
short keep_alive;
|
||||||
size_t content_length;
|
ssize_t content_length;
|
||||||
|
|
||||||
/** PUBLIC **/
|
/** PUBLIC **/
|
||||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||||
|
@@ -27,9 +27,10 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
/* parser->flags */
|
/* parser->flags */
|
||||||
#define EATING 0x01
|
#define EATING 0x01
|
||||||
#define ERROR 0x02
|
#define ERROR 0x02
|
||||||
#define CHUNKED 0x04
|
#define CHUNKED 0x04
|
||||||
|
#define EAT_FOREVER 0x10
|
||||||
|
|
||||||
static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
||||||
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
||||||
@@ -79,7 +80,7 @@ do { \
|
|||||||
parser->method = 0; \
|
parser->method = 0; \
|
||||||
parser->version = HTTP_VERSION_OTHER; \
|
parser->version = HTTP_VERSION_OTHER; \
|
||||||
parser->keep_alive = -1; \
|
parser->keep_alive = -1; \
|
||||||
parser->content_length = 0; \
|
parser->content_length = -1; \
|
||||||
parser->body_read = 0
|
parser->body_read = 0
|
||||||
|
|
||||||
#define END_REQUEST \
|
#define END_REQUEST \
|
||||||
@@ -226,6 +227,7 @@ do { \
|
|||||||
}
|
}
|
||||||
|
|
||||||
action content_length {
|
action content_length {
|
||||||
|
if (parser->content_length == -1) parser->content_length = 0;
|
||||||
if (parser->content_length > INT_MAX) {
|
if (parser->content_length > INT_MAX) {
|
||||||
parser->flags |= ERROR;
|
parser->flags |= ERROR;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -281,11 +283,25 @@ do { \
|
|||||||
if (parser->flags & CHUNKED) {
|
if (parser->flags & CHUNKED) {
|
||||||
fnext ChunkedBody;
|
fnext ChunkedBody;
|
||||||
} else {
|
} else {
|
||||||
/* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */
|
/* this is pretty stupid. i'd prefer to combine this with
|
||||||
parser->chunk_size = parser->content_length;
|
* skip_chunk_data */
|
||||||
|
if (parser->content_length < 0) {
|
||||||
|
/* If we didn't get a content length; if not keep-alive
|
||||||
|
* just read body until EOF */
|
||||||
|
if (!http_parser_should_keep_alive(parser)) {
|
||||||
|
parser->flags |= EAT_FOREVER;
|
||||||
|
parser->chunk_size = REMAINING;
|
||||||
|
} else {
|
||||||
|
/* Otherwise, if keep-alive, then assume the message
|
||||||
|
* has no body. */
|
||||||
|
parser->chunk_size = parser->content_length = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parser->chunk_size = parser->content_length;
|
||||||
|
}
|
||||||
p += 1;
|
p += 1;
|
||||||
|
|
||||||
SKIP_BODY(MIN(REMAINING, parser->content_length));
|
SKIP_BODY(MIN(REMAINING, parser->chunk_size));
|
||||||
|
|
||||||
if (callback_return_value != 0) {
|
if (callback_return_value != 0) {
|
||||||
parser->flags |= ERROR;
|
parser->flags |= ERROR;
|
||||||
@@ -444,11 +460,27 @@ http_parser_execute (http_parser *parser, const char *buffer, size_t len)
|
|||||||
{
|
{
|
||||||
size_t tmp; // REMOVE ME this is extremely hacky
|
size_t tmp; // REMOVE ME this is extremely hacky
|
||||||
int callback_return_value = 0;
|
int callback_return_value = 0;
|
||||||
const char *p, *pe;
|
const char *p, *pe, *eof;
|
||||||
int cs = parser->cs;
|
int cs = parser->cs;
|
||||||
|
|
||||||
p = buffer;
|
p = buffer;
|
||||||
pe = buffer+len;
|
pe = buffer+len;
|
||||||
|
eof = len ? NULL : pe;
|
||||||
|
|
||||||
|
if (parser->flags & EAT_FOREVER) {
|
||||||
|
if (len == 0) {
|
||||||
|
if (parser->on_message_complete) {
|
||||||
|
callback_return_value = parser->on_message_complete(parser);
|
||||||
|
if (callback_return_value != 0) parser->flags |= ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parser->on_body) {
|
||||||
|
callback_return_value = parser->on_body(parser, p, len);
|
||||||
|
if (callback_return_value != 0) parser->flags |= ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
if (0 < parser->chunk_size && (parser->flags & EATING)) {
|
if (0 < parser->chunk_size && (parser->flags & EATING)) {
|
||||||
/* eat body */
|
/* eat body */
|
||||||
|
39
test.c
39
test.c
@@ -344,6 +344,45 @@ const struct message responses[] =
|
|||||||
"</BODY></HTML>\r\n"
|
"</BODY></HTML>\r\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
, {.name= "no content-length response"
|
||||||
|
,.type= HTTP_RESPONSE
|
||||||
|
,.raw= "HTTP/1.1 200 OK\r\n"
|
||||||
|
"Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
|
||||||
|
"Server: Apache\r\n"
|
||||||
|
"X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
|
||||||
|
"Content-Type: text/xml; charset=utf-8\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
|
||||||
|
" <SOAP-ENV:Body>\n"
|
||||||
|
" <SOAP-ENV:Fault>\n"
|
||||||
|
" <faultcode>SOAP-ENV:Client</faultcode>\n"
|
||||||
|
" <faultstring>Client Error</faultstring>\n"
|
||||||
|
" </SOAP-ENV:Fault>\n"
|
||||||
|
" </SOAP-ENV:Body>\n"
|
||||||
|
"</SOAP-ENV:Envelope>"
|
||||||
|
,.should_keep_alive= FALSE
|
||||||
|
,.status_code= 200
|
||||||
|
,.num_headers= 5
|
||||||
|
,.headers=
|
||||||
|
{ { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
|
||||||
|
, { "Server", "Apache" }
|
||||||
|
, { "X-Powered-By", "Servlet/2.5 JSP/2.1" }
|
||||||
|
, { "Content-Type", "text/xml; charset=utf-8" }
|
||||||
|
, { "Connection", "close" }
|
||||||
|
}
|
||||||
|
,.body= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
|
||||||
|
" <SOAP-ENV:Body>\n"
|
||||||
|
" <SOAP-ENV:Fault>\n"
|
||||||
|
" <faultcode>SOAP-ENV:Client</faultcode>\n"
|
||||||
|
" <faultstring>Client Error</faultstring>\n"
|
||||||
|
" </SOAP-ENV:Fault>\n"
|
||||||
|
" </SOAP-ENV:Body>\n"
|
||||||
|
"</SOAP-ENV:Envelope>"
|
||||||
|
}
|
||||||
|
|
||||||
, {.name= "404 no headers no body"
|
, {.name= "404 no headers no body"
|
||||||
,.type= HTTP_RESPONSE
|
,.type= HTTP_RESPONSE
|
||||||
,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
|
,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
|
||||||
|
Reference in New Issue
Block a user