diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c index 01d17fb6237..dd9fab91517 100644 --- a/src/core/lib/http/parser.c +++ b/src/core/lib/http/parser.c @@ -171,8 +171,8 @@ static int add_header(grpc_http_parser *parser) { while (cur != end && (*cur == ' ' || *cur == '\t')) { cur++; } - GPR_ASSERT(end - cur >= 2); - hdr.value = buf2str(cur, (size_t)(end - cur) - 2); + GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length); + hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length); if (parser->type == GRPC_HTTP_RESPONSE) { hdr_count = &parser->http.response.hdr_count; @@ -207,7 +207,7 @@ static int finish_line(grpc_http_parser *parser) { parser->state = GRPC_HTTP_HEADERS; break; case GRPC_HTTP_HEADERS: - if (parser->cur_line_length == 2) { + if (parser->cur_line_length == parser->cur_line_end_length) { parser->state = GRPC_HTTP_BODY; break; } @@ -247,6 +247,30 @@ static int addbyte_body(grpc_http_parser *parser, uint8_t byte) { return 1; } +static int check_line(grpc_http_parser *parser) { + if (parser->cur_line_length >= 2 && + parser->cur_line[parser->cur_line_length - 2] == '\r' && + parser->cur_line[parser->cur_line_length - 1] == '\n') { + return 1; + } + + // HTTP request with \n\r line termiantors. + else if (parser->cur_line_length >= 2 && + parser->cur_line[parser->cur_line_length - 2] == '\n' && + parser->cur_line[parser->cur_line_length - 1] == '\r') { + return 1; + } + + // HTTP request with only \n line terminators. + else if (parser->cur_line_length >= 1 && + parser->cur_line[parser->cur_line_length - 1] == '\n') { + parser->cur_line_end_length = 1; + return 1; + } + + return 0; +} + static int addbyte(grpc_http_parser *parser, uint8_t byte) { switch (parser->state) { case GRPC_HTTP_FIRST_LINE: @@ -259,9 +283,7 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) { } parser->cur_line[parser->cur_line_length] = byte; parser->cur_line_length++; - if (parser->cur_line_length >= 2 && - parser->cur_line[parser->cur_line_length - 2] == '\r' && - parser->cur_line[parser->cur_line_length - 1] == '\n') { + if (check_line(parser)) { return finish_line(parser); } else { return 1; @@ -277,6 +299,7 @@ void grpc_http_parser_init(grpc_http_parser *parser) { memset(parser, 0, sizeof(*parser)); parser->state = GRPC_HTTP_FIRST_LINE; parser->type = GRPC_HTTP_UNKNOWN; + parser->cur_line_end_length = 2; } void grpc_http_parser_destroy(grpc_http_parser *parser) { diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h index 8bd73f649ab..f0dc06cf3a1 100644 --- a/src/core/lib/http/parser.h +++ b/src/core/lib/http/parser.h @@ -105,6 +105,7 @@ typedef struct { uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH]; size_t cur_line_length; + size_t cur_line_end_length; } grpc_http_parser; void grpc_http_parser_init(grpc_http_parser *parser); diff --git a/test/core/http/parser_test.c b/test/core/http/parser_test.c index 10936754d96..7fdf60cc2b1 100644 --- a/test/core/http/parser_test.c +++ b/test/core/http/parser_test.c @@ -238,6 +238,11 @@ int main(int argc, char **argv) { "\r\n" "hello world!", 200, "hello world!", "xyz", "abc", NULL); + test_succeeds(split_modes[i], + "HTTP/1.1 200 OK\n" + "\n" + "abc", + 200, "abc", NULL); test_request_succeeds(split_modes[i], "GET / HTTP/1.0\r\n" "\r\n", @@ -264,6 +269,11 @@ int main(int argc, char **argv) { "xyz", "GET", GRPC_HTTP_HTTP10, "/", "xyz", "xyz", "abc", NULL); + test_request_succeeds(split_modes[i], + "GET / HTTP/1.0\n" + "\n" + "xyz", + "GET", GRPC_HTTP_HTTP10, "/", "xyz", NULL); test_fails(split_modes[i], "HTTP/1.0\r\n"); test_fails(split_modes[i], "HTTP/1.2\r\n"); test_fails(split_modes[i], "HTTP/1.0 000 XYX\r\n"); @@ -281,6 +291,7 @@ int main(int argc, char **argv) { test_fails(split_modes[i], "GET / HTTP/0.0\r\n"); test_fails(split_modes[i], "GET / ____/1.0\r\n"); test_fails(split_modes[i], "GET / HTTP/1.2\r\n"); + test_fails(split_modes[i], "GET / HTTP/1.0\n"); tmp1 = gpr_malloc(2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); memset(tmp1, 'a', 2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH - 1);