more robust chunked response parsing (fixes #2554)
handle chunked parts across multiple reads fixes https://redmine.lighttpd.net/issues/2554 where Happstack performs multiple writes to send HTTP chunked header, HTTP chunked body, and CRLF ending HTTP chunked body supercedes https://github.com/lighttpd/weighttp/pull/8 handle additional chunked case of split CR and LF reference https://github.com/lighttpd/weighttp/pull/9/files#r52358620 thx stbuehler detect CR not followed by LF (error) handle NIL in chunked stream (should not occur in HTTP headers or chunked header, but could occur in chunked body) x-ref: "weighttp closing connection too early(?)" https://redmine.lighttpd.net/issues/2554 github: closes #8, closes #9
This commit is contained in:
parent
8f2147e429
commit
925707722f
39
src/client.c
39
src/client.c
|
@ -337,6 +337,11 @@ static uint8_t client_parse(Client *client, int size) {
|
|||
status_code += *str - '0';
|
||||
}
|
||||
|
||||
// look for next \r\n
|
||||
end = memchr(end, '\r', client->buffer_offset);
|
||||
if (!end || *(end+1) != '\n')
|
||||
return (!end || *(end+1) == '\0') && client->buffer_offset < 1024 ? 1 : 0;
|
||||
|
||||
if (status_code >= 200 && status_code < 300) {
|
||||
client->worker->stats.req_2xx++;
|
||||
client->status_success = 1;
|
||||
|
@ -352,19 +357,14 @@ static uint8_t client_parse(Client *client, int size) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// look for next \r\n
|
||||
end = strchr(end, '\r');
|
||||
if (!end || *(end+1) != '\n')
|
||||
return 0;
|
||||
|
||||
client->parser_offset = end + 2 - client->buffer;
|
||||
client->parser_state = PARSER_HEADER;
|
||||
case PARSER_HEADER:
|
||||
//printf("parse (HEADER)\n");
|
||||
/* look for Content-Length and Connection header */
|
||||
while (NULL != (end = strchr(&client->buffer[client->parser_offset], '\r'))) {
|
||||
while (NULL != (end = memchr(&client->buffer[client->parser_offset], '\r', client->buffer_offset - client->parser_offset))) {
|
||||
if (*(end+1) != '\n')
|
||||
return 0;
|
||||
return *(end+1) == '\0' && client->buffer_offset - client->parser_offset < 1024 ? 1 : 0;
|
||||
|
||||
if (end == &client->buffer[client->parser_offset]) {
|
||||
/* body reached */
|
||||
|
@ -449,25 +449,33 @@ static uint8_t client_parse(Client *client, int size) {
|
|||
else if (*str >= 'a' && *str <= 'z')
|
||||
client->chunk_size += 10 + *str - 'a';
|
||||
else
|
||||
return 0;
|
||||
return 0; /*(src < end checked above)*/
|
||||
}
|
||||
|
||||
str = strstr(str, "\r\n");
|
||||
if (!str)
|
||||
return 0;
|
||||
if (str[0] != '\r') {
|
||||
str = memchr(str, '\r', end-str);
|
||||
if (!str) {
|
||||
client->chunk_size = -1;
|
||||
return size < 1024 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
if (str[1] != '\n') {
|
||||
client->chunk_size = -1;
|
||||
return str+1 == end ? 1 : 0;
|
||||
}
|
||||
str += 2;
|
||||
|
||||
//printf("---------- chunk size: %"PRIi64", %d read, %d offset, data: '%s'\n", client->chunk_size, size, client->parser_offset, str);
|
||||
|
||||
size -= str - &client->buffer[client->parser_offset];
|
||||
client->parser_offset = str - client->buffer;
|
||||
|
||||
if (client->chunk_size == 0) {
|
||||
/* chunk of size 0 marks end of content body */
|
||||
client->state = CLIENT_END;
|
||||
client->success = client->status_success ? 1 : 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size -= str - &client->buffer[client->parser_offset];
|
||||
client->parser_offset = str - client->buffer;
|
||||
}
|
||||
|
||||
/* consume chunk till chunk_size is reached */
|
||||
|
@ -482,6 +490,9 @@ static uint8_t client_parse(Client *client, int size) {
|
|||
//printf("---------- chunk consuming: %d, received: %"PRIi64" of %"PRIi64", offset: %d\n", consume_max, client->chunk_received, client->chunk_size, client->parser_offset);
|
||||
|
||||
if (client->chunk_received == client->chunk_size) {
|
||||
if (size - consume_max < 2)
|
||||
return 1;
|
||||
|
||||
if (client->buffer[client->parser_offset] != '\r' || client->buffer[client->parser_offset+1] != '\n')
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue