From b97fdb051307afe018bf22b5f09cc83e83fec6e9 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Apr 2012 15:24:59 +0200 Subject: [PATCH] Don't assert() on whitespace in URL. Be lenient about tabs and form feeds in non-strict mode. --- http_parser.c | 20 +++++++++++++++-- test.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/http_parser.c b/http_parser.c index acd4130..0c11eb8 100644 --- a/http_parser.c +++ b/http_parser.c @@ -184,11 +184,18 @@ static const int8_t unhex[256] = }; +#if HTTP_PARSER_STRICT +# define T 0 +#else +# define T 1 +#endif + + static const uint8_t normal_url_char[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, T, 0, 0, T, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ @@ -218,6 +225,7 @@ static const uint8_t normal_url_char[256] = { /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 1, 1, 1, 1, 1, 1, 1, 0, }; +#undef T enum state { s_dead = 1 /* important that this is > 0 */ @@ -396,7 +404,15 @@ int http_message_needs_eof(http_parser *parser); static enum state parse_url_char(enum state s, const char ch) { - assert(!isspace(ch)); + if (ch == ' ' || ch == '\r' || ch == '\n') { + return s_dead; + } + +#if HTTP_PARSER_STRICT + if (ch == '\t' || ch == '\f') { + return s_dead; + } +#endif switch (s) { case s_req_spaces_before_url: diff --git a/test.c b/test.c index db4fc32..b5df08c 100644 --- a/test.c +++ b/test.c @@ -2072,6 +2072,68 @@ const struct url_test url_tests[] = ,.is_connect=1 ,.rv=1 } + +, {.name="space in URL" + ,.url="/foo bar/" + ,.rv=1 /* s_dead */ + } + +, {.name="carriage return in URL" + ,.url="/foo\rbar/" + ,.rv=1 /* s_dead */ + } + +, {.name="line feed in URL" + ,.url="/foo\nbar/" + ,.rv=1 /* s_dead */ + } + +#if HTTP_PARSER_STRICT + +, {.name="tab in URL" + ,.url="/foo\tbar/" + ,.rv=1 /* s_dead */ + } + +, {.name="form feed in URL" + ,.url="/foo\fbar/" + ,.rv=1 /* s_dead */ + } + +#else /* !HTTP_PARSER_STRICT */ + +, {.name="tab in URL" + ,.url="/foo\tbar/" + ,.u= + {.field_set=(1 << UF_PATH) + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 0, 0 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 0, 9 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + +, {.name="form feed in URL" + ,.url="/foo\fbar/" + ,.u= + {.field_set=(1 << UF_PATH) + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 0, 0 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 0, 9 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } +#endif }; void