From 9dfaa67f2b74a11d7cc2a58d28961547b19462fc Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Sat, 7 Jul 2012 22:14:12 +0200 Subject: [PATCH 01/14] Check host on url with hostname:port --- test.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/test.c b/test.c index 6d8c004..23bcf5d 100644 --- a/test.c +++ b/test.c @@ -50,6 +50,7 @@ struct message { char query_string[MAX_ELEMENT_SIZE]; char body[MAX_ELEMENT_SIZE]; size_t body_size; + const char *host; uint16_t port; int num_headers; enum { NONE=0, FIELD, VALUE } last_header_element; @@ -649,6 +650,7 @@ const struct message requests[] = ,.fragment= "" ,.request_path= "" ,.request_url= "http://hypnotoad.org:1234?hail=all" + ,.host= "hypnotoad.org" ,.port= 1234 ,.num_headers= 0 ,.headers= { } @@ -669,6 +671,7 @@ const struct message requests[] = ,.fragment= "" ,.request_path= "" ,.request_url= "http://hypnotoad.org:1234" + ,.host= "hypnotoad.org" ,.port= 1234 ,.num_headers= 0 ,.headers= { } @@ -1794,6 +1797,10 @@ message_eq (int index, const struct message *expected) abort(); } + if (expected->host) { + MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST); + } + m->port = (u.field_set & (1 << UF_PORT)) ? u.port : 0; @@ -1971,6 +1978,24 @@ const struct url_test url_tests[] = ,.rv=0 } +, {.name="proxy request with port" + ,.url="http://hostname:444/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) + ,.port=444 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 7, 8 } /* UF_HOST */ + ,{ 16, 3 } /* UF_PORT */ + ,{ 19, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + , {.name="CONNECT request" ,.url="hostname:443" ,.is_connect=1 @@ -2007,6 +2032,24 @@ const struct url_test url_tests[] = ,.rv=0 } +, {.name="proxy ipv6 request with port" + ,.url="http://[1:2::3:4]:67/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) + ,.port=67 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 8 } /* UF_HOST */ + ,{ 18, 2 } /* UF_PORT */ + ,{ 20, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + } + } + ,.rv=0 + } + , {.name="CONNECT ipv6 address" ,.url="[1:2::3:4]:443" ,.is_connect=1 @@ -2043,6 +2086,79 @@ const struct url_test url_tests[] = ,.rv=0 } +, {.name="space URL encoded" + ,.url="/toto.html?toto=a%20b" + ,.is_connect=0 + ,.u= + {.field_set= (1< Date: Sat, 7 Jul 2012 23:29:43 +0200 Subject: [PATCH 02/14] Add url_parser tool --- .gitignore | 1 + Makefile | 8 +++++++- url_parser.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 url_parser.c diff --git a/.gitignore b/.gitignore index 8631bd8..3b868c5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ tags test test_g test_fast +url_parser *.mk *.Makefile *.so diff --git a/Makefile b/Makefile index 8d90f8d..d9bf839 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,12 @@ test_fast: http_parser.o test.o http_parser.h test.o: test.c http_parser.h Makefile $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c test.c -o $@ +url_parser: http_parser_g.o url_parser.o + $(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o url_parser.o -o $@ + +url_parser.o: url_parser.c http_parser.h Makefile + $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c url_parser.c -o $@ + http_parser.o: http_parser.c http_parser.h Makefile $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c @@ -53,6 +59,6 @@ tags: http_parser.c http_parser.h test.c ctags $^ clean: - rm -f *.o *.a test test_fast test_g http_parser.tar tags libhttp_parser.so libhttp_parser.o + rm -f *.o *.a test test_fast test_g url_parser http_parser.tar tags libhttp_parser.so libhttp_parser.o .PHONY: clean package test-run test-run-timed test-valgrind diff --git a/url_parser.c b/url_parser.c new file mode 100644 index 0000000..c1f3ef0 --- /dev/null +++ b/url_parser.c @@ -0,0 +1,47 @@ +#include "http_parser.h" +#include +#include + +void +dump_url (const char *url, const struct http_parser_url *u) +{ + char part[512]; + unsigned int i; + + printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port); + for (i = 0; i < UF_MAX; i++) { + if ((u->field_set & (1 << i)) == 0) { + printf("\tfield_data[%u]: unset\n", i); + continue; + } + + memcpy(part, url + u->field_data[i].off, u->field_data[i].len); + part[u->field_data[i].len] = '\0'; + + printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n", + i, + u->field_data[i].off, + u->field_data[i].len, + part); + } +} + +int main(int argc, char ** argv) { + if (argc != 3) { + printf("Syntax : %s connect|get url\n", argv[0]); + return 1; + } + struct http_parser_url u; + int len = strlen(argv[2]); + int connect = strcmp("connect", argv[1]) == 0 ? 1 : 0; + printf("Parsing %s, connect %d\n", argv[2], connect); + + int result = http_parser_parse_url(argv[2], len, connect, &u); + if (result != 0) { + printf("Parse error : %d\n", result); + return result; + } + printf("Parse ok, result : \n"); + dump_url(argv[2], &u); + return 0; +} \ No newline at end of file From ed8475d49f8d60a61f684c802a7c4c0d8d539fca Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Sun, 8 Jul 2012 01:10:43 +0200 Subject: [PATCH 03/14] Refactor host parsing to allow basic auth management --- http_parser.c | 224 +++++++++++++++++++++++++++++++------------------- 1 file changed, 139 insertions(+), 85 deletions(-) diff --git a/http_parser.c b/http_parser.c index 0c11eb8..7125665 100644 --- a/http_parser.c +++ b/http_parser.c @@ -254,12 +254,7 @@ enum state , s_req_schema_slash , s_req_schema_slash_slash , s_req_host_start - , s_req_host_v6_start - , s_req_host_v6 - , s_req_host_v6_end , s_req_host - , s_req_port_start - , s_req_port , s_req_path , s_req_query_string_start , s_req_query_string @@ -337,6 +332,17 @@ enum header_states , h_connection_close }; +enum http_host_state + { + s_http_host_dead = 1 + , s_http_host_start + , s_http_host_v6_start + , s_http_host + , s_http_host_v6 + , s_http_host_v6_end + , s_http_host_port_start + , s_http_host_port +}; /* Macros for character classes; depends on strict-mode */ #define CR '\r' @@ -456,61 +462,17 @@ parse_url_char(enum state s, const char ch) break; case s_req_host_start: - if (ch == '[') { - return s_req_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_req_host; - } - - break; - case s_req_host: - if (IS_HOST_CHAR(ch)) { - return s_req_host; - } - - /* FALLTHROUGH */ - case s_req_host_v6_end: - switch (ch) { - case ':': - return s_req_port_start; - - case '/': - return s_req_path; - - case '?': - return s_req_query_string_start; - } - - break; - - case s_req_host_v6: - if (ch == ']') { - return s_req_host_v6_end; - } - - /* FALLTHROUGH */ - case s_req_host_v6_start: - if (IS_HEX(ch) || ch == ':') { - return s_req_host_v6; + if (ch == '/') { + return s_req_path; } - break; - - case s_req_port: - switch (ch) { - case '/': - return s_req_path; - case '?': - return s_req_query_string_start; + if (ch == '?') { + return s_req_query_string_start; } - /* FALLTHROUGH */ - case s_req_port_start: - if (IS_NUM(ch)) { - return s_req_port; + if (IS_ALPHANUM(ch) || ch == '_' || ch == '@' || ch == '[' || ch == ']' || ch == '.' || ch == '-' || ch == '%' || ch == ';' || ch == ':' || ch == '&' || ch == '=' || ch == '+' || ch == '$' || ch == ',') { + return s_req_host; } break; @@ -633,12 +595,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_host_start: - case s_req_host_v6_start: - case s_req_host_v6: - case s_req_host_v6_end: case s_req_host: - case s_req_port_start: - case s_req_port: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: @@ -1015,9 +972,6 @@ size_t http_parser_execute (http_parser *parser, case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_host_start: - case s_req_host_v6_start: - case s_req_host_v6: - case s_req_port_start: { switch (ch) { /* No whitespace allowed here */ @@ -1038,8 +992,6 @@ size_t http_parser_execute (http_parser *parser, } case s_req_host: - case s_req_host_v6_end: - case s_req_port: case s_req_path: case s_req_query_string_start: case s_req_query_string: @@ -1938,6 +1890,122 @@ http_errno_description(enum http_errno err) { return http_strerror_tab[err].description; } +static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch) { + switch(s) { + case s_http_host_start: + if (ch == '[') { + return s_http_host_v6_start; + } + + if (IS_HOST_CHAR(ch)) { + return s_http_host; + } + + break; + + case s_http_host: + + if (IS_HOST_CHAR(ch)) { + return s_http_host; + } + + /* FALLTHROUGH */ + case s_http_host_v6_end: + if (ch == ':') { + return s_http_host_port_start; + } + + break; + + case s_http_host_v6: + if (ch == ']') { + return s_http_host_v6_end; + } + + /* FALLTHROUGH */ + case s_http_host_v6_start: + if (IS_HEX(ch) || ch == ':') { + return s_http_host_v6; + } + + break; + + case s_http_host_port: + case s_http_host_port_start: + if (IS_NUM(ch)) { + return s_http_host_port; + } + + break; + + default: + break; + } + return s_http_host_dead; +} + +int http_parse_host(const char * buf, struct http_parser_url *u) { + enum http_host_state s; + + int i; + int start = u->field_data[UF_HOST].off; + int len = u->field_data[UF_HOST].len; + + u->field_data[UF_HOST].len = 0; + + i = 0; + s = s_http_host_start; + + for(; i < len; i ++) { + char ch = buf[start + i]; + enum http_host_state new_s = http_parse_host_char(s, ch); + if (new_s == s_http_host_dead) { + return 1; + } + + switch(new_s) { + case s_http_host: + if (s != s_http_host) { + u->field_data[UF_HOST].off = start + i; + } + u->field_data[UF_HOST].len ++; + break; + + case s_http_host_v6: + if (s != s_http_host_v6) { + u->field_data[UF_HOST].off = start + i; + } + u->field_data[UF_HOST].len ++; + break; + + case s_http_host_port: + if (s != s_http_host_port) { + u->field_data[UF_PORT].off = start + i; + u->field_data[UF_PORT].len = 0; + u->field_set |= (1 << UF_PORT); + } + u->field_data[UF_PORT].len ++; + break; + + default: + break; + } + s = new_s; + } + + /* Make sure we don't end somewhere unexpected */ + switch (s) { + case s_http_host_v6_start: + case s_http_host_v6: + case s_http_host_port_start: + return 1; + default: + break; + } + + return 0; +} + int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u) @@ -1962,9 +2030,6 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_host_start: - case s_req_host_v6_start: - case s_req_host_v6_end: - case s_req_port_start: case s_req_query_string_start: case s_req_fragment_start: continue; @@ -1974,14 +2039,9 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, break; case s_req_host: - case s_req_host_v6: uf = UF_HOST; break; - case s_req_port: - uf = UF_PORT; - break; - case s_req_path: uf = UF_PATH; break; @@ -2012,21 +2072,15 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, old_uf = uf; } - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; + if ((u->field_set & (1 << UF_HOST)) != 0) { + if (http_parse_host(buf, u) != 0) { + return 1; + } } - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_req_host_v6_start: - case s_req_host_v6: - case s_req_host_v6_end: - case s_req_host: - case s_req_port_start: + /* CONNECT requests can only contain "hostname:port" */ + if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { return 1; - default: - break; } if (u->field_set & (1 << UF_PORT)) { From 79650962763cd4b849c9c9689953b9d848732f0e Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Sun, 8 Jul 2012 01:44:31 +0200 Subject: [PATCH 04/14] User info implementation --- http_parser.c | 54 +++++++++++++++++++++++++++++++++++++++++---------- http_parser.h | 3 ++- test.c | 13 +++++++++++++ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/http_parser.c b/http_parser.c index 7125665..5ea352d 100644 --- a/http_parser.c +++ b/http_parser.c @@ -335,6 +335,8 @@ enum header_states enum http_host_state { s_http_host_dead = 1 + , s_http_userinfo_start + , s_http_userinfo , s_http_host_start , s_http_host_v6_start , s_http_host @@ -352,6 +354,8 @@ enum http_host_state #define IS_NUM(c) ((c) >= '0' && (c) <= '9') #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) +#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || (c) == ')') +#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || (c) == '$' || (c) == ',') #if HTTP_PARSER_STRICT #define TOKEN(c) (tokens[(unsigned char)c]) @@ -408,7 +412,7 @@ int http_message_needs_eof(http_parser *parser); * URL and non-URL states by looking for these. */ static enum state -parse_url_char(enum state s, const char ch) +parse_url_char(enum state s, const char ch, int * found_at) { if (ch == ' ' || ch == '\r' || ch == '\n') { return s_dead; @@ -471,7 +475,14 @@ parse_url_char(enum state s, const char ch) return s_req_query_string_start; } - if (IS_ALPHANUM(ch) || ch == '_' || ch == '@' || ch == '[' || ch == ']' || ch == '.' || ch == '-' || ch == '%' || ch == ';' || ch == ':' || ch == '&' || ch == '=' || ch == '+' || ch == '$' || ch == ',') { + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { + return s_req_host; + } + + if (ch == '@') { + if (found_at) { + *found_at = 1; + } return s_req_host; } @@ -959,7 +970,7 @@ size_t http_parser_execute (http_parser *parser, parser->state = s_req_host_start; } - parser->state = parse_url_char((enum state)parser->state, ch); + parser->state = parse_url_char((enum state)parser->state, ch, 0); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -981,7 +992,7 @@ size_t http_parser_execute (http_parser *parser, SET_ERRNO(HPE_INVALID_URL); goto error; default: - parser->state = parse_url_char((enum state)parser->state, ch); + parser->state = parse_url_char((enum state)parser->state, ch, 0); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -1013,7 +1024,7 @@ size_t http_parser_execute (http_parser *parser, CALLBACK_DATA(url); break; default: - parser->state = parse_url_char((enum state)parser->state, ch); + parser->state = parse_url_char((enum state)parser->state, ch, 0); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -1890,8 +1901,20 @@ http_errno_description(enum http_errno err) { return http_strerror_tab[err].description; } -static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch) { +static enum http_host_state +http_parse_host_char(enum http_host_state s, const char ch) { switch(s) { + case s_http_userinfo: + case s_http_userinfo_start: + if (ch == '@') { + return s_http_host_start; + } + + if (IS_USERINFO_CHAR(ch)) { + return s_http_userinfo; + } + break; + case s_http_host_start: if (ch == '[') { return s_http_host_v6_start; @@ -1944,7 +1967,7 @@ static enum http_host_state http_parse_host_char(enum http_host_state s, const c return s_http_host_dead; } -int http_parse_host(const char * buf, struct http_parser_url *u) { +int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { enum http_host_state s; int i; @@ -1954,11 +1977,12 @@ int http_parse_host(const char * buf, struct http_parser_url *u) { u->field_data[UF_HOST].len = 0; i = 0; - s = s_http_host_start; + s = found_at ? s_http_userinfo_start : s_http_host_start; for(; i < len; i ++) { char ch = buf[start + i]; enum http_host_state new_s = http_parse_host_char(s, ch); + if (new_s == s_http_host_dead) { return 1; } @@ -1987,6 +2011,15 @@ int http_parse_host(const char * buf, struct http_parser_url *u) { u->field_data[UF_PORT].len ++; break; + case s_http_userinfo: + if (s != s_http_userinfo) { + u->field_data[UF_USERINFO].off = start + i; + u->field_data[UF_USERINFO].len = 0; + u->field_set |= (1 << UF_USERINFO); + } + u->field_data[UF_USERINFO].len ++; + break; + default: break; } @@ -2013,13 +2046,14 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, enum state s; const char *p; enum http_parser_url_fields uf, old_uf; + int found_at = 0; u->port = u->field_set = 0; s = is_connect ? s_req_host_start : s_req_spaces_before_url; uf = old_uf = UF_MAX; for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); + s = parse_url_char(s, *p, &found_at); /* Figure out the next field that we're operating on */ switch (s) { @@ -2073,7 +2107,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, } if ((u->field_set & (1 << UF_HOST)) != 0) { - if (http_parse_host(buf, u) != 0) { + if (http_parse_host(buf, u, found_at) != 0) { return 1; } } diff --git a/http_parser.h b/http_parser.h index 8ed4180..dc15473 100644 --- a/http_parser.h +++ b/http_parser.h @@ -256,7 +256,8 @@ enum http_parser_url_fields , UF_PATH = 3 , UF_QUERY = 4 , UF_FRAGMENT = 5 - , UF_MAX = 6 + , UF_USERINFO = 6 + , UF_MAX = 7 }; diff --git a/test.c b/test.c index 23bcf5d..f7dfcfe 100644 --- a/test.c +++ b/test.c @@ -1973,6 +1973,7 @@ const struct url_test url_tests[] = ,{ 15, 1 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -1991,6 +1992,7 @@ const struct url_test url_tests[] = ,{ 19, 1 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2009,6 +2011,7 @@ const struct url_test url_tests[] = ,{ 0, 0 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2027,6 +2030,7 @@ const struct url_test url_tests[] = ,{ 17, 1 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2045,6 +2049,7 @@ const struct url_test url_tests[] = ,{ 20, 1 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2063,6 +2068,7 @@ const struct url_test url_tests[] = ,{ 0, 0 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2081,6 +2087,7 @@ const struct url_test url_tests[] = ,{ 17, 12 } /* UF_PATH */ ,{ 30,187 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2099,6 +2106,7 @@ const struct url_test url_tests[] = ,{ 0, 10 } /* UF_PATH */ ,{ 11, 10 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2118,6 +2126,7 @@ const struct url_test url_tests[] = ,{ 0, 10 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 11, 4 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2136,6 +2145,7 @@ const struct url_test url_tests[] = ,{ 29, 6 } /* UF_PATH */ ,{ 36, 69 } /* UF_QUERY */ ,{106, 7 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2154,6 +2164,7 @@ const struct url_test url_tests[] = ,{ 20, 8 } /* UF_PATH */ ,{ 29, 12 } /* UF_QUERY */ ,{ 42, 4 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2254,6 +2265,7 @@ const struct url_test url_tests[] = ,{ 0, 9 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 @@ -2270,6 +2282,7 @@ const struct url_test url_tests[] = ,{ 0, 9 } /* UF_PATH */ ,{ 0, 0 } /* UF_QUERY */ ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ } } ,.rv=0 From fe31fe8bf0ff8028123698d3097347ffdff3c214 Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Sun, 8 Jul 2012 02:00:31 +0200 Subject: [PATCH 05/14] Add tests on user info --- test.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/test.c b/test.c index f7dfcfe..a9fc05f 100644 --- a/test.c +++ b/test.c @@ -51,6 +51,7 @@ struct message { char body[MAX_ELEMENT_SIZE]; size_t body_size; const char *host; + const char *userinfo; uint16_t port; int num_headers; enum { NONE=0, FIELD, VALUE } last_header_element; @@ -631,6 +632,7 @@ const struct message requests[] = ,.fragment= "" ,.request_path= "" ,.request_url= "http://hypnotoad.org?hail=all" + ,.host= "hypnotoad.org" ,.num_headers= 0 ,.headers= { } ,.body= "" @@ -873,6 +875,28 @@ const struct message requests[] = ,.body= "" } +#define PROXY_WITH_BASIC_AUTH 33 +, {.name= "host:port and basic_auth" + ,.type= HTTP_REQUEST + ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.fragment= "" + ,.request_path= "/toto" + ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto" + ,.host= "hypnotoad.org" + ,.userinfo= "a%12:b!&*$" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + + , {.name= NULL } /* sentinel */ }; @@ -1801,6 +1825,10 @@ message_eq (int index, const struct message *expected) MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST); } + if (expected->userinfo) { + MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO); + } + m->port = (u.field_set & (1 << UF_PORT)) ? u.port : 0; @@ -2170,6 +2198,25 @@ const struct url_test url_tests[] = ,.rv=0 } +, {.name="complex URL with basic auth from node js url parser doc" + ,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash" + ,.is_connect=0 + ,.u= + {.field_set= (1< Date: Sun, 8 Jul 2012 11:58:18 +0200 Subject: [PATCH 06/14] Small refactoring, add edge cases --- http_parser.c | 30 +++++++++++++++++------------- test.c | 28 +++++++++++++++++++--------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/http_parser.c b/http_parser.c index 5ea352d..99a6b62 100644 --- a/http_parser.c +++ b/http_parser.c @@ -1967,21 +1967,21 @@ http_parse_host_char(enum http_host_state s, const char ch) { return s_http_host_dead; } -int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { +#include + +static int +http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { enum http_host_state s; - int i; - int start = u->field_data[UF_HOST].off; - int len = u->field_data[UF_HOST].len; + const char *p; + size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; u->field_data[UF_HOST].len = 0; - i = 0; s = found_at ? s_http_userinfo_start : s_http_host_start; - for(; i < len; i ++) { - char ch = buf[start + i]; - enum http_host_state new_s = http_parse_host_char(s, ch); + for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { + enum http_host_state new_s = http_parse_host_char(s, *p); if (new_s == s_http_host_dead) { return 1; @@ -1990,21 +1990,21 @@ int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { switch(new_s) { case s_http_host: if (s != s_http_host) { - u->field_data[UF_HOST].off = start + i; + u->field_data[UF_HOST].off = p - buf; } u->field_data[UF_HOST].len ++; break; case s_http_host_v6: if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = start + i; + u->field_data[UF_HOST].off = p - buf; } u->field_data[UF_HOST].len ++; break; case s_http_host_port: if (s != s_http_host_port) { - u->field_data[UF_PORT].off = start + i; + u->field_data[UF_PORT].off = p - buf; u->field_data[UF_PORT].len = 0; u->field_set |= (1 << UF_PORT); } @@ -2013,7 +2013,7 @@ int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { case s_http_userinfo: if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = start + i; + u->field_data[UF_USERINFO].off = p - buf ; u->field_data[UF_USERINFO].len = 0; u->field_set |= (1 << UF_USERINFO); } @@ -2028,9 +2028,12 @@ int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { /* Make sure we don't end somewhere unexpected */ switch (s) { + case s_http_host_start: case s_http_host_v6_start: case s_http_host_v6: case s_http_host_port_start: + case s_http_userinfo: + case s_http_userinfo_start: return 1; default: break; @@ -2106,7 +2109,8 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, old_uf = uf; } - if ((u->field_set & (1 << UF_HOST)) != 0) { + // host must be present if there is a schema + if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { if (http_parse_host(buf, u, found_at) != 0) { return 1; } diff --git a/test.c b/test.c index a9fc05f..f50ece7 100644 --- a/test.c +++ b/test.c @@ -2258,7 +2258,7 @@ const struct url_test url_tests[] = ,.rv=1 /* s_dead */ } -, {.name="basic auth with space url encoded" +, {.name="proxy basic auth with space url encoded" ,.url="http://a%20:b@host.com/" ,.is_connect=0 ,.u= @@ -2282,12 +2282,12 @@ const struct url_test url_tests[] = ,.rv=1 /* s_dead */ } -, {.name="double : in URL" +, {.name="proxy double : in URL" ,.url="http://hostname::443/" ,.rv=1 /* s_dead */ } -, {.name="basic auth with double :" +, {.name="proxy basic auth with double :" ,.url="http://a::b@host.com/" ,.is_connect=0 ,.u= @@ -2311,7 +2311,7 @@ const struct url_test url_tests[] = ,.rv=1 /* s_dead */ } -, {.name="empty basic auth" +, {.name="proxy empty basic auth" ,.url="http://@hostname/fo" ,.u= {.field_set= (1< Date: Sun, 8 Jul 2012 16:06:22 +0200 Subject: [PATCH 07/14] Add tests --- test.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test.c b/test.c index f50ece7..c85e95c 100644 --- a/test.c +++ b/test.c @@ -2045,6 +2045,12 @@ const struct url_test url_tests[] = ,.rv=0 } +, {.name="CONNECT request but not connect" + ,.url="hostname:443" + ,.is_connect=0 + ,.rv=1 + } + , {.name="proxy ipv6 request" ,.url="http://[1:2::3:4]/" ,.is_connect=0 @@ -2362,11 +2368,16 @@ const struct url_test url_tests[] = ,.rv=0 } -, {.name="proxy only basic auth" +, {.name="proxy only empty basic auth" ,.url="http://@/fo" ,.rv=1 /* s_dead */ } +, {.name="proxy only basic auth" + ,.url="http://toto@/fo" + ,.rv=1 /* s_dead */ + } + , {.name="proxy emtpy hostname" ,.url="http:///fo" ,.rv=1 /* s_dead */ From bb29f437411d8aa6403bc4e1d913320b783e6417 Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Tue, 17 Jul 2012 08:37:39 +0200 Subject: [PATCH 08/14] Coding style improvment --- http_parser.c | 21 +++++++++++---------- test.c | 16 +++++++++++----- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/http_parser.c b/http_parser.c index 99a6b62..ed5477f 100644 --- a/http_parser.c +++ b/http_parser.c @@ -354,8 +354,12 @@ enum http_host_state #define IS_NUM(c) ((c) >= '0' && (c) <= '9') #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || (c) == '$' || (c) == ',') +#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ + (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ + (c) == ')') +#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ + (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ + (c) == '$' || (c) == ',') #if HTTP_PARSER_STRICT #define TOKEN(c) (tokens[(unsigned char)c]) @@ -412,7 +416,7 @@ int http_message_needs_eof(http_parser *parser); * URL and non-URL states by looking for these. */ static enum state -parse_url_char(enum state s, const char ch, int * found_at) +parse_url_char(enum state s, const char ch, int *found_at) { if (ch == ' ' || ch == '\r' || ch == '\n') { return s_dead; @@ -970,7 +974,7 @@ size_t http_parser_execute (http_parser *parser, parser->state = s_req_host_start; } - parser->state = parse_url_char((enum state)parser->state, ch, 0); + parser->state = parse_url_char((enum state)parser->state, ch, NULL); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -992,7 +996,7 @@ size_t http_parser_execute (http_parser *parser, SET_ERRNO(HPE_INVALID_URL); goto error; default: - parser->state = parse_url_char((enum state)parser->state, ch, 0); + parser->state = parse_url_char((enum state)parser->state, ch, NULL); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -1024,7 +1028,7 @@ size_t http_parser_execute (http_parser *parser, CALLBACK_DATA(url); break; default: - parser->state = parse_url_char((enum state)parser->state, ch, 0); + parser->state = parse_url_char((enum state)parser->state, ch, NULL); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -1927,7 +1931,6 @@ http_parse_host_char(enum http_host_state s, const char ch) { break; case s_http_host: - if (IS_HOST_CHAR(ch)) { return s_http_host; } @@ -1967,8 +1970,6 @@ http_parse_host_char(enum http_host_state s, const char ch) { return s_http_host_dead; } -#include - static int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { enum http_host_state s; @@ -2109,7 +2110,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, old_uf = uf; } - // host must be present if there is a schema + /* host must be present if there is a schema */ if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { if (http_parse_host(buf, u, found_at) != 0) { return 1; diff --git a/test.c b/test.c index c85e95c..787beab 100644 --- a/test.c +++ b/test.c @@ -2109,7 +2109,9 @@ const struct url_test url_tests[] = } , {.name="extra ? in query string" - ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css" + ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css," + "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css," + "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css" ,.is_connect=0 ,.u= {.field_set=(1< Date: Tue, 17 Jul 2012 08:48:46 +0200 Subject: [PATCH 09/14] Use new state instead of pointer --- http_parser.c | 28 +++++++++++++++++++--------- test.c | 6 ++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/http_parser.c b/http_parser.c index ed5477f..8784af6 100644 --- a/http_parser.c +++ b/http_parser.c @@ -255,6 +255,7 @@ enum state , s_req_schema_slash_slash , s_req_host_start , s_req_host + , s_req_host_with_at , s_req_path , s_req_query_string_start , s_req_query_string @@ -416,7 +417,7 @@ int http_message_needs_eof(http_parser *parser); * URL and non-URL states by looking for these. */ static enum state -parse_url_char(enum state s, const char ch, int *found_at) +parse_url_char(enum state s, const char ch) { if (ch == ' ' || ch == '\r' || ch == '\n') { return s_dead; @@ -469,6 +470,12 @@ parse_url_char(enum state s, const char ch, int *found_at) break; + case s_req_host_with_at: + if (ch == '@') { + return s_dead; + } + + /* FALLTHROUGH */ case s_req_host_start: case s_req_host: if (ch == '/') { @@ -484,10 +491,7 @@ parse_url_char(enum state s, const char ch, int *found_at) } if (ch == '@') { - if (found_at) { - *found_at = 1; - } - return s_req_host; + return s_req_host_with_at; } break; @@ -611,6 +615,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_schema_slash_slash: case s_req_host_start: case s_req_host: + case s_req_host_with_at: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: @@ -974,7 +979,7 @@ size_t http_parser_execute (http_parser *parser, parser->state = s_req_host_start; } - parser->state = parse_url_char((enum state)parser->state, ch, NULL); + parser->state = parse_url_char((enum state)parser->state, ch); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -996,7 +1001,7 @@ size_t http_parser_execute (http_parser *parser, SET_ERRNO(HPE_INVALID_URL); goto error; default: - parser->state = parse_url_char((enum state)parser->state, ch, NULL); + parser->state = parse_url_char((enum state)parser->state, ch); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -1007,6 +1012,7 @@ size_t http_parser_execute (http_parser *parser, } case s_req_host: + case s_req_host_with_at: case s_req_path: case s_req_query_string_start: case s_req_query_string: @@ -1028,7 +1034,7 @@ size_t http_parser_execute (http_parser *parser, CALLBACK_DATA(url); break; default: - parser->state = parse_url_char((enum state)parser->state, ch, NULL); + parser->state = parse_url_char((enum state)parser->state, ch); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; @@ -2057,7 +2063,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, uf = old_uf = UF_MAX; for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p, &found_at); + s = parse_url_char(s, *p); /* Figure out the next field that we're operating on */ switch (s) { @@ -2076,6 +2082,10 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, uf = UF_SCHEMA; break; + case s_req_host_with_at: + found_at = 1; + + /* FALLTROUGH */ case s_req_host: uf = UF_HOST; break; diff --git a/test.c b/test.c index 787beab..73b0289 100644 --- a/test.c +++ b/test.c @@ -2229,6 +2229,12 @@ const struct url_test url_tests[] = ,.rv=0 } +, {.name="double @" + ,.url="http://a:b@@hostname:443/" + ,.is_connect=0 + ,.rv=1 + } + , {.name="proxy empty host" ,.url="http://:443/" ,.is_connect=0 From 1d3a0ec75250272979cc7e77ceed721c98307297 Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Wed, 25 Jul 2012 00:12:40 +0200 Subject: [PATCH 10/14] Use fixed_length printf instead of copying data and do null-termination --- test.c | 9 +++------ url_parser.c | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/test.c b/test.c index 73b0289..1ca8f05 100644 --- a/test.c +++ b/test.c @@ -2453,7 +2453,6 @@ const struct url_test url_tests[] = void dump_url (const char *url, const struct http_parser_url *u) { - char part[512]; unsigned int i; printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port); @@ -2463,14 +2462,12 @@ dump_url (const char *url, const struct http_parser_url *u) continue; } - memcpy(part, url + u->field_data[i].off, u->field_data[i].len); - part[u->field_data[i].len] = '\0'; - - printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n", + printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n", i, u->field_data[i].off, u->field_data[i].len, - part); + u->field_data[i].len, + url + u->field_data[i].off); } } diff --git a/url_parser.c b/url_parser.c index c1f3ef0..b1f9c97 100644 --- a/url_parser.c +++ b/url_parser.c @@ -5,7 +5,6 @@ void dump_url (const char *url, const struct http_parser_url *u) { - char part[512]; unsigned int i; printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port); @@ -15,14 +14,12 @@ dump_url (const char *url, const struct http_parser_url *u) continue; } - memcpy(part, url + u->field_data[i].off, u->field_data[i].len); - part[u->field_data[i].len] = '\0'; - - printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n", + printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n", i, u->field_data[i].off, u->field_data[i].len, - part); + u->field_data[i].len, + url + u->field_data[i].off); } } From 7f1b191d6fce976cd44ff4463bca7c28762e4561 Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Wed, 25 Jul 2012 00:13:54 +0200 Subject: [PATCH 11/14] Minor speed improvment --- http_parser.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/http_parser.c b/http_parser.c index 8784af6..3671df2 100644 --- a/http_parser.c +++ b/http_parser.c @@ -486,14 +486,14 @@ parse_url_char(enum state s, const char ch) return s_req_query_string_start; } - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_host; - } - if (ch == '@') { return s_req_host_with_at; } + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { + return s_req_host; + } + break; case s_req_path: From 148984cd8ddcf8c4f9c2c1baf22b6df5c7848c03 Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Wed, 25 Jul 2012 00:16:53 +0200 Subject: [PATCH 12/14] Rename s_req_host* to be compliant with RFC 2396 --- http_parser.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/http_parser.c b/http_parser.c index 3671df2..380026e 100644 --- a/http_parser.c +++ b/http_parser.c @@ -253,9 +253,9 @@ enum state , s_req_schema , s_req_schema_slash , s_req_schema_slash_slash - , s_req_host_start - , s_req_host - , s_req_host_with_at + , s_req_server_start + , s_req_server + , s_req_server_with_at , s_req_path , s_req_query_string_start , s_req_query_string @@ -465,19 +465,19 @@ parse_url_char(enum state s, const char ch) case s_req_schema_slash_slash: if (ch == '/') { - return s_req_host_start; + return s_req_server_start; } break; - case s_req_host_with_at: + case s_req_server_with_at: if (ch == '@') { return s_dead; } /* FALLTHROUGH */ - case s_req_host_start: - case s_req_host: + case s_req_server_start: + case s_req_server: if (ch == '/') { return s_req_path; } @@ -487,11 +487,11 @@ parse_url_char(enum state s, const char ch) } if (ch == '@') { - return s_req_host_with_at; + return s_req_server_with_at; } if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_host; + return s_req_server; } break; @@ -613,9 +613,9 @@ size_t http_parser_execute (http_parser *parser, case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: - case s_req_host_start: - case s_req_host: - case s_req_host_with_at: + case s_req_server_start: + case s_req_server: + case s_req_server_with_at: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: @@ -976,7 +976,7 @@ size_t http_parser_execute (http_parser *parser, MARK(url); if (parser->method == HTTP_CONNECT) { - parser->state = s_req_host_start; + parser->state = s_req_server_start; } parser->state = parse_url_char((enum state)parser->state, ch); @@ -991,7 +991,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: - case s_req_host_start: + case s_req_server_start: { switch (ch) { /* No whitespace allowed here */ @@ -1011,8 +1011,8 @@ size_t http_parser_execute (http_parser *parser, break; } - case s_req_host: - case s_req_host_with_at: + case s_req_server: + case s_req_server_with_at: case s_req_path: case s_req_query_string_start: case s_req_query_string: @@ -2059,7 +2059,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, int found_at = 0; u->port = u->field_set = 0; - s = is_connect ? s_req_host_start : s_req_spaces_before_url; + s = is_connect ? s_req_server_start : s_req_spaces_before_url; uf = old_uf = UF_MAX; for (p = buf; p < buf + buflen; p++) { @@ -2073,7 +2073,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, /* Skip delimeters */ case s_req_schema_slash: case s_req_schema_slash_slash: - case s_req_host_start: + case s_req_server_start: case s_req_query_string_start: case s_req_fragment_start: continue; @@ -2082,11 +2082,11 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, uf = UF_SCHEMA; break; - case s_req_host_with_at: + case s_req_server_with_at: found_at = 1; /* FALLTROUGH */ - case s_req_host: + case s_req_server: uf = UF_HOST; break; From 50faa793f47025032021b7c75fd1eb3f7010f873 Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Wed, 25 Jul 2012 00:20:03 +0200 Subject: [PATCH 13/14] Coding style : remove space before ++ --- http_parser.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/http_parser.c b/http_parser.c index 380026e..b8c092a 100644 --- a/http_parser.c +++ b/http_parser.c @@ -1999,14 +1999,14 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { if (s != s_http_host) { u->field_data[UF_HOST].off = p - buf; } - u->field_data[UF_HOST].len ++; + u->field_data[UF_HOST].len++; break; case s_http_host_v6: if (s != s_http_host_v6) { u->field_data[UF_HOST].off = p - buf; } - u->field_data[UF_HOST].len ++; + u->field_data[UF_HOST].len++; break; case s_http_host_port: @@ -2015,7 +2015,7 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { u->field_data[UF_PORT].len = 0; u->field_set |= (1 << UF_PORT); } - u->field_data[UF_PORT].len ++; + u->field_data[UF_PORT].len++; break; case s_http_userinfo: @@ -2024,7 +2024,7 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { u->field_data[UF_USERINFO].len = 0; u->field_set |= (1 << UF_USERINFO); } - u->field_data[UF_USERINFO].len ++; + u->field_data[UF_USERINFO].len++; break; default: From a828edaf6af085e8fe9ad4a38267a1e75eb3269a Mon Sep 17 00:00:00 2001 From: Bertrand Paquet Date: Wed, 25 Jul 2012 00:36:04 +0200 Subject: [PATCH 14/14] Add a comment --- http_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/http_parser.c b/http_parser.c index b8c092a..8122376 100644 --- a/http_parser.c +++ b/http_parser.c @@ -2121,6 +2121,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, } /* host must be present if there is a schema */ + /* parsing http:///toto will fail */ if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { if (http_parse_host(buf, u, found_at) != 0) { return 1;