Allow grpc_http_parser to optionally accept a wider range of line endings.

pull/6105/head
Matthew Iselin 9 years ago committed by Matthew Iselin
parent e0cd55e353
commit 7151af9465
  1. 35
      src/core/lib/http/parser.c
  2. 1
      src/core/lib/http/parser.h
  3. 11
      test/core/http/parser_test.c

@ -171,8 +171,8 @@ static int add_header(grpc_http_parser *parser) {
while (cur != end && (*cur == ' ' || *cur == '\t')) { while (cur != end && (*cur == ' ' || *cur == '\t')) {
cur++; cur++;
} }
GPR_ASSERT(end - cur >= 2); GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
hdr.value = buf2str(cur, (size_t)(end - cur) - 2); hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
if (parser->type == GRPC_HTTP_RESPONSE) { if (parser->type == GRPC_HTTP_RESPONSE) {
hdr_count = &parser->http.response.hdr_count; hdr_count = &parser->http.response.hdr_count;
@ -207,7 +207,7 @@ static int finish_line(grpc_http_parser *parser) {
parser->state = GRPC_HTTP_HEADERS; parser->state = GRPC_HTTP_HEADERS;
break; break;
case GRPC_HTTP_HEADERS: 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; parser->state = GRPC_HTTP_BODY;
break; break;
} }
@ -247,6 +247,30 @@ static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
return 1; 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) { static int addbyte(grpc_http_parser *parser, uint8_t byte) {
switch (parser->state) { switch (parser->state) {
case GRPC_HTTP_FIRST_LINE: 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[parser->cur_line_length] = byte;
parser->cur_line_length++; parser->cur_line_length++;
if (parser->cur_line_length >= 2 && if (check_line(parser)) {
parser->cur_line[parser->cur_line_length - 2] == '\r' &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
return finish_line(parser); return finish_line(parser);
} else { } else {
return 1; return 1;
@ -277,6 +299,7 @@ void grpc_http_parser_init(grpc_http_parser *parser) {
memset(parser, 0, sizeof(*parser)); memset(parser, 0, sizeof(*parser));
parser->state = GRPC_HTTP_FIRST_LINE; parser->state = GRPC_HTTP_FIRST_LINE;
parser->type = GRPC_HTTP_UNKNOWN; parser->type = GRPC_HTTP_UNKNOWN;
parser->cur_line_end_length = 2;
} }
void grpc_http_parser_destroy(grpc_http_parser *parser) { void grpc_http_parser_destroy(grpc_http_parser *parser) {

@ -105,6 +105,7 @@ typedef struct {
uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH]; uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH];
size_t cur_line_length; size_t cur_line_length;
size_t cur_line_end_length;
} grpc_http_parser; } grpc_http_parser;
void grpc_http_parser_init(grpc_http_parser *parser); void grpc_http_parser_init(grpc_http_parser *parser);

@ -238,6 +238,11 @@ int main(int argc, char **argv) {
"\r\n" "\r\n"
"hello world!", "hello world!",
200, "hello world!", "xyz", "abc", NULL); 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], test_request_succeeds(split_modes[i],
"GET / HTTP/1.0\r\n" "GET / HTTP/1.0\r\n"
"\r\n", "\r\n",
@ -264,6 +269,11 @@ int main(int argc, char **argv) {
"xyz", "xyz",
"GET", GRPC_HTTP_HTTP10, "/", "xyz", "xyz", "abc", "GET", GRPC_HTTP_HTTP10, "/", "xyz", "xyz", "abc",
NULL); 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.0\r\n");
test_fails(split_modes[i], "HTTP/1.2\r\n"); test_fails(split_modes[i], "HTTP/1.2\r\n");
test_fails(split_modes[i], "HTTP/1.0 000 XYX\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 / HTTP/0.0\r\n");
test_fails(split_modes[i], "GET / ____/1.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.2\r\n");
test_fails(split_modes[i], "GET / HTTP/1.0\n");
tmp1 = gpr_malloc(2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); tmp1 = gpr_malloc(2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
memset(tmp1, 'a', 2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH - 1); memset(tmp1, 'a', 2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH - 1);

Loading…
Cancel
Save