|  | @@ -43,7 +43,7 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static http_parser *parser;
 | 
	
		
			
				|  |  | +static http_parser parser;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct message {
 | 
	
		
			
				|  |  |    const char *name; // for debugging purposes
 | 
	
	
		
			
				|  | @@ -153,10 +153,10 @@ const struct message requests[] =
 | 
	
		
			
				|  |  |    ,.body= ""
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define DUMBFUCK 2
 | 
	
		
			
				|  |  | -, {.name= "dumbfuck"
 | 
	
		
			
				|  |  | +#define DUMBLUCK 2
 | 
	
		
			
				|  |  | +, {.name= "dumbluck"
 | 
	
		
			
				|  |  |    ,.type= HTTP_REQUEST
 | 
	
		
			
				|  |  | -  ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
 | 
	
		
			
				|  |  | +  ,.raw= "GET /dumbluck HTTP/1.1\r\n"
 | 
	
		
			
				|  |  |           "aaaaaaaaaaaaa:++++++++++\r\n"
 | 
	
		
			
				|  |  |           "\r\n"
 | 
	
		
			
				|  |  |    ,.should_keep_alive= TRUE
 | 
	
	
		
			
				|  | @@ -166,8 +166,8 @@ const struct message requests[] =
 | 
	
		
			
				|  |  |    ,.method= HTTP_GET
 | 
	
		
			
				|  |  |    ,.query_string= ""
 | 
	
		
			
				|  |  |    ,.fragment= ""
 | 
	
		
			
				|  |  | -  ,.request_path= "/dumbfuck"
 | 
	
		
			
				|  |  | -  ,.request_url= "/dumbfuck"
 | 
	
		
			
				|  |  | +  ,.request_path= "/dumbluck"
 | 
	
		
			
				|  |  | +  ,.request_url= "/dumbluck"
 | 
	
		
			
				|  |  |    ,.num_headers= 1
 | 
	
		
			
				|  |  |    ,.headers=
 | 
	
		
			
				|  |  |      { { "aaaaaaaaaaaaa",  "++++++++++" }
 | 
	
	
		
			
				|  | @@ -371,13 +371,13 @@ const struct message requests[] =
 | 
	
		
			
				|  |  |    ,.chunk_lengths= { 5, 6 }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
 | 
	
		
			
				|  |  | -, {.name= "with bullshit after the length"
 | 
	
		
			
				|  |  | +#define CHUNKED_W_NONSENSE_AFTER_LENGTH 11
 | 
	
		
			
				|  |  | +, {.name= "with nonsense after the length"
 | 
	
		
			
				|  |  |    ,.type= HTTP_REQUEST
 | 
	
		
			
				|  |  | -  ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
 | 
	
		
			
				|  |  | +  ,.raw= "POST /chunked_w_nonsense_after_length HTTP/1.1\r\n"
 | 
	
		
			
				|  |  |           "Transfer-Encoding: chunked\r\n"
 | 
	
		
			
				|  |  |           "\r\n"
 | 
	
		
			
				|  |  | -         "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
 | 
	
		
			
				|  |  | +         "5; ilovew3;whattheluck=aretheseparametersfor\r\nhello\r\n"
 | 
	
		
			
				|  |  |           "6; blahblah; blah\r\n world\r\n"
 | 
	
		
			
				|  |  |           "0\r\n"
 | 
	
		
			
				|  |  |           "\r\n"
 | 
	
	
		
			
				|  | @@ -388,8 +388,8 @@ const struct message requests[] =
 | 
	
		
			
				|  |  |    ,.method= HTTP_POST
 | 
	
		
			
				|  |  |    ,.query_string= ""
 | 
	
		
			
				|  |  |    ,.fragment= ""
 | 
	
		
			
				|  |  | -  ,.request_path= "/chunked_w_bullshit_after_length"
 | 
	
		
			
				|  |  | -  ,.request_url= "/chunked_w_bullshit_after_length"
 | 
	
		
			
				|  |  | +  ,.request_path= "/chunked_w_nonsense_after_length"
 | 
	
		
			
				|  |  | +  ,.request_url= "/chunked_w_nonsense_after_length"
 | 
	
		
			
				|  |  |    ,.num_headers= 1
 | 
	
		
			
				|  |  |    ,.headers=
 | 
	
		
			
				|  |  |      { { "Transfer-Encoding", "chunked" }
 | 
	
	
		
			
				|  | @@ -1173,6 +1173,26 @@ const struct message requests[] =
 | 
	
		
			
				|  |  |    ,.headers= { { "Host", "example.com" } }
 | 
	
		
			
				|  |  |    ,.body= ""
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define SOURCE_ICE_REQUEST 42
 | 
	
		
			
				|  |  | +, {.name = "source request"
 | 
	
		
			
				|  |  | +  ,.type= HTTP_REQUEST
 | 
	
		
			
				|  |  | +  ,.raw= "SOURCE /music/sweet/music ICE/1.0\r\n"
 | 
	
		
			
				|  |  | +         "Host: example.com\r\n"
 | 
	
		
			
				|  |  | +         "\r\n"
 | 
	
		
			
				|  |  | +  ,.should_keep_alive= FALSE
 | 
	
		
			
				|  |  | +  ,.message_complete_on_eof= FALSE
 | 
	
		
			
				|  |  | +  ,.http_major= 1
 | 
	
		
			
				|  |  | +  ,.http_minor= 0
 | 
	
		
			
				|  |  | +  ,.method= HTTP_SOURCE
 | 
	
		
			
				|  |  | +  ,.request_path= "/music/sweet/music"
 | 
	
		
			
				|  |  | +  ,.request_url= "/music/sweet/music"
 | 
	
		
			
				|  |  | +  ,.query_string= ""
 | 
	
		
			
				|  |  | +  ,.fragment= ""
 | 
	
		
			
				|  |  | +  ,.num_headers= 1
 | 
	
		
			
				|  |  | +  ,.headers= { { "Host", "example.com" } }
 | 
	
		
			
				|  |  | +  ,.body= ""
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* * R E S P O N S E S * */
 | 
	
	
		
			
				|  | @@ -2010,7 +2030,7 @@ strlncpy(char *dst, size_t len, const char *src, size_t n)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  request_url_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |    strlncat(messages[num_messages].request_url,
 | 
	
		
			
				|  |  |             sizeof(messages[num_messages].request_url),
 | 
	
		
			
				|  |  |             buf,
 | 
	
	
		
			
				|  | @@ -2021,7 +2041,7 @@ request_url_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  header_field_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |    struct message *m = &messages[num_messages];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (m->last_header_element != FIELD)
 | 
	
	
		
			
				|  | @@ -2040,7 +2060,7 @@ header_field_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  header_value_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |    struct message *m = &messages[num_messages];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    strlncat(m->headers[m->num_headers-1][1],
 | 
	
	
		
			
				|  | @@ -2069,7 +2089,7 @@ check_body_is_final (const http_parser *p)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  body_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |    strlncat(messages[num_messages].body,
 | 
	
		
			
				|  |  |             sizeof(messages[num_messages].body),
 | 
	
		
			
				|  |  |             buf,
 | 
	
	
		
			
				|  | @@ -2083,7 +2103,7 @@ body_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  count_body_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |    assert(buf);
 | 
	
		
			
				|  |  |    messages[num_messages].body_size += len;
 | 
	
		
			
				|  |  |    check_body_is_final(p);
 | 
	
	
		
			
				|  | @@ -2093,7 +2113,8 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  message_begin_cb (http_parser *p)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  | +  assert(!messages[num_messages].message_begin_cb_called);
 | 
	
		
			
				|  |  |    messages[num_messages].message_begin_cb_called = TRUE;
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -2101,21 +2122,22 @@ message_begin_cb (http_parser *p)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  headers_complete_cb (http_parser *p)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | -  messages[num_messages].method = parser->method;
 | 
	
		
			
				|  |  | -  messages[num_messages].status_code = parser->status_code;
 | 
	
		
			
				|  |  | -  messages[num_messages].http_major = parser->http_major;
 | 
	
		
			
				|  |  | -  messages[num_messages].http_minor = parser->http_minor;
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  | +  messages[num_messages].method = parser.method;
 | 
	
		
			
				|  |  | +  messages[num_messages].status_code = parser.status_code;
 | 
	
		
			
				|  |  | +  messages[num_messages].http_major = parser.http_major;
 | 
	
		
			
				|  |  | +  messages[num_messages].http_minor = parser.http_minor;
 | 
	
		
			
				|  |  |    messages[num_messages].headers_complete_cb_called = TRUE;
 | 
	
		
			
				|  |  | -  messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
 | 
	
		
			
				|  |  | +  messages[num_messages].should_keep_alive = http_should_keep_alive(&parser);
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  message_complete_cb (http_parser *p)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | -  if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  | +  if (messages[num_messages].should_keep_alive !=
 | 
	
		
			
				|  |  | +      http_should_keep_alive(&parser))
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
 | 
	
		
			
				|  |  |                      "value in both on_message_complete and on_headers_complete "
 | 
	
	
		
			
				|  | @@ -2146,7 +2168,7 @@ message_complete_cb (http_parser *p)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  response_status_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    messages[num_messages].status_cb_called = TRUE;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2160,7 +2182,7 @@ response_status_cb (http_parser *p, const char *buf, size_t len)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  chunk_header_cb (http_parser *p)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |    int chunk_idx = messages[num_messages].num_chunks;
 | 
	
		
			
				|  |  |    messages[num_messages].num_chunks++;
 | 
	
		
			
				|  |  |    if (chunk_idx < MAX_CHUNKS) {
 | 
	
	
		
			
				|  | @@ -2173,7 +2195,7 @@ chunk_header_cb (http_parser *p)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  chunk_complete_cb (http_parser *p)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  assert(p == parser);
 | 
	
		
			
				|  |  | +  assert(p == &parser);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Here we want to verify that each chunk_header_cb is matched by a
 | 
	
		
			
				|  |  |     * chunk_complete_cb, so not only should the total number of calls to
 | 
	
	
		
			
				|  | @@ -2378,7 +2400,7 @@ connect_headers_complete_cb (http_parser *p)
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  connect_message_complete_cb (http_parser *p)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
 | 
	
		
			
				|  |  | +  messages[num_messages].should_keep_alive = http_should_keep_alive(&parser);
 | 
	
		
			
				|  |  |    return message_complete_cb(p);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2451,30 +2473,15 @@ void
 | 
	
		
			
				|  |  |  parser_init (enum http_parser_type type)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    num_messages = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  assert(parser == NULL);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  parser = malloc(sizeof(http_parser));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  http_parser_init(parser, type);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +  http_parser_init(&parser, type);
 | 
	
		
			
				|  |  |    memset(&messages, 0, sizeof messages);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void
 | 
	
		
			
				|  |  | -parser_free ()
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  assert(parser);
 | 
	
		
			
				|  |  | -  free(parser);
 | 
	
		
			
				|  |  | -  parser = NULL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  size_t parse (const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    size_t nparsed;
 | 
	
		
			
				|  |  |    currently_parsing_eof = (len == 0);
 | 
	
		
			
				|  |  | -  nparsed = http_parser_execute(parser, &settings, buf, len);
 | 
	
		
			
				|  |  | +  nparsed = http_parser_execute(&parser, &settings, buf, len);
 | 
	
		
			
				|  |  |    return nparsed;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2482,7 +2489,7 @@ size_t parse_count_body (const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    size_t nparsed;
 | 
	
		
			
				|  |  |    currently_parsing_eof = (len == 0);
 | 
	
		
			
				|  |  | -  nparsed = http_parser_execute(parser, &settings_count_body, buf, len);
 | 
	
		
			
				|  |  | +  nparsed = http_parser_execute(&parser, &settings_count_body, buf, len);
 | 
	
		
			
				|  |  |    return nparsed;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2493,7 +2500,7 @@ size_t parse_pause (const char *buf, size_t len)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    currently_parsing_eof = (len == 0);
 | 
	
		
			
				|  |  |    current_pause_parser = &s;
 | 
	
		
			
				|  |  | -  nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
 | 
	
		
			
				|  |  | +  nparsed = http_parser_execute(&parser, current_pause_parser, buf, len);
 | 
	
		
			
				|  |  |    return nparsed;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2501,7 +2508,7 @@ size_t parse_connect (const char *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    size_t nparsed;
 | 
	
		
			
				|  |  |    currently_parsing_eof = (len == 0);
 | 
	
		
			
				|  |  | -  nparsed = http_parser_execute(parser, &settings_connect, buf, len);
 | 
	
		
			
				|  |  | +  nparsed = http_parser_execute(&parser, &settings_connect, buf, len);
 | 
	
		
			
				|  |  |    return nparsed;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2721,7 +2728,7 @@ static void
 | 
	
		
			
				|  |  |  print_error (const char *raw, size_t error_location)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    fprintf(stderr, "\n*** %s ***\n\n",
 | 
	
		
			
				|  |  | -          http_errno_description(HTTP_PARSER_ERRNO(parser)));
 | 
	
		
			
				|  |  | +          http_errno_description(HTTP_PARSER_ERRNO(&parser)));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    int this_line = 0, char_len = 0;
 | 
	
		
			
				|  |  |    size_t i, j, len = strlen(raw), error_location_line = 0;
 | 
	
	
		
			
				|  | @@ -3264,6 +3271,24 @@ const struct url_test url_tests[] =
 | 
	
		
			
				|  |  |    ,.rv=1 /* s_dead */
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +, {.name="empty url"
 | 
	
		
			
				|  |  | +  ,.url=""
 | 
	
		
			
				|  |  | +  ,.is_connect=0
 | 
	
		
			
				|  |  | +  ,.rv=1
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +, {.name="NULL url"
 | 
	
		
			
				|  |  | +  ,.url=NULL
 | 
	
		
			
				|  |  | +  ,.is_connect=0
 | 
	
		
			
				|  |  | +  ,.rv=1
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +, {.name="full of spaces url"
 | 
	
		
			
				|  |  | +  ,.url="  "
 | 
	
		
			
				|  |  | +  ,.is_connect=0
 | 
	
		
			
				|  |  | +  ,.rv=1
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #if HTTP_PARSER_STRICT
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  , {.name="tab in URL"
 | 
	
	
		
			
				|  | @@ -3348,7 +3373,7 @@ test_parse_url (void)
 | 
	
		
			
				|  |  |      memset(&u, 0, sizeof(u));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      rv = http_parser_parse_url(test->url,
 | 
	
		
			
				|  |  | -                               strlen(test->url),
 | 
	
		
			
				|  |  | +                               test->url ? strlen(test->url) : 0,
 | 
	
		
			
				|  |  |                                 test->is_connect,
 | 
	
		
			
				|  |  |                                 &u);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -3389,6 +3414,14 @@ test_method_str (void)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void
 | 
	
		
			
				|  |  | +test_status_str (void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  assert(0 == strcmp("OK", http_status_str(HTTP_STATUS_OK)));
 | 
	
		
			
				|  |  | +  assert(0 == strcmp("Not Found", http_status_str(HTTP_STATUS_NOT_FOUND)));
 | 
	
		
			
				|  |  | +  assert(0 == strcmp("<unknown>", http_status_str(1337)));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void
 | 
	
		
			
				|  |  |  test_message (const struct message *message)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    size_t raw_len = strlen(message->raw);
 | 
	
	
		
			
				|  | @@ -3402,9 +3435,18 @@ test_message (const struct message *message)
 | 
	
		
			
				|  |  |      size_t msg2len = raw_len - msg1len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (msg1len) {
 | 
	
		
			
				|  |  | +      assert(num_messages == 0);
 | 
	
		
			
				|  |  | +      messages[0].headers_complete_cb_called = FALSE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        read = parse(msg1, msg1len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      if (message->upgrade && parser->upgrade && num_messages > 0) {
 | 
	
		
			
				|  |  | +      if (!messages[0].headers_complete_cb_called && parser.nread != read) {
 | 
	
		
			
				|  |  | +        assert(parser.nread == read);
 | 
	
		
			
				|  |  | +        print_error(msg1, read);
 | 
	
		
			
				|  |  | +        abort();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (message->upgrade && parser.upgrade && num_messages > 0) {
 | 
	
		
			
				|  |  |          messages[num_messages - 1].upgrade = msg1 + read;
 | 
	
		
			
				|  |  |          goto test;
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -3418,7 +3460,7 @@ test_message (const struct message *message)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      read = parse(msg2, msg2len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (message->upgrade && parser->upgrade) {
 | 
	
		
			
				|  |  | +    if (message->upgrade && parser.upgrade) {
 | 
	
		
			
				|  |  |        messages[num_messages - 1].upgrade = msg2 + read;
 | 
	
		
			
				|  |  |        goto test;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -3443,8 +3485,6 @@ test_message (const struct message *message)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(!message_eq(0, 0, message)) abort();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    parser_free();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -3480,8 +3520,6 @@ test_message_count_body (const struct message *message)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if(!message_eq(0, 0, message)) abort();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  parser_free();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void
 | 
	
	
		
			
				|  | @@ -3494,11 +3532,9 @@ test_simple_type (const char *buf,
 | 
	
		
			
				|  |  |    enum http_errno err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    parse(buf, strlen(buf));
 | 
	
		
			
				|  |  | -  err = HTTP_PARSER_ERRNO(parser);
 | 
	
		
			
				|  |  | +  err = HTTP_PARSER_ERRNO(&parser);
 | 
	
		
			
				|  |  |    parse(NULL, 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  parser_free();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    /* In strict mode, allow us to pass with an unexpected HPE_STRICT as
 | 
	
		
			
				|  |  |     * long as the caller isn't expecting success.
 | 
	
		
			
				|  |  |     */
 | 
	
	
		
			
				|  | @@ -3838,7 +3874,7 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    read = parse(total, strlen(total));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (parser->upgrade) {
 | 
	
		
			
				|  |  | +  if (parser.upgrade) {
 | 
	
		
			
				|  |  |      upgrade_message_fix(total, read, 3, r1, r2, r3);
 | 
	
		
			
				|  |  |      goto test;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -3865,8 +3901,6 @@ test:
 | 
	
		
			
				|  |  |    if (!message_eq(0, 0, r1)) abort();
 | 
	
		
			
				|  |  |    if (message_count > 1 && !message_eq(1, 0, r2)) abort();
 | 
	
		
			
				|  |  |    if (message_count > 2 && !message_eq(2, 0, r3)) abort();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  parser_free();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* SCAN through every possible breaking to make sure the
 | 
	
	
		
			
				|  | @@ -3920,9 +3954,17 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
 | 
	
		
			
				|  |  |          strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
 | 
	
		
			
				|  |  |          buf3[buf3_len] = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        assert(num_messages == 0);
 | 
	
		
			
				|  |  | +        messages[0].headers_complete_cb_called = FALSE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          read = parse(buf1, buf1_len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if (parser->upgrade) goto test;
 | 
	
		
			
				|  |  | +        if (!messages[0].headers_complete_cb_called && parser.nread != read) {
 | 
	
		
			
				|  |  | +          print_error(buf1, read);
 | 
	
		
			
				|  |  | +          goto error;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (parser.upgrade) goto test;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if (read != buf1_len) {
 | 
	
		
			
				|  |  |            print_error(buf1, read);
 | 
	
	
		
			
				|  | @@ -3931,7 +3973,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          read += parse(buf2, buf2_len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if (parser->upgrade) goto test;
 | 
	
		
			
				|  |  | +        if (parser.upgrade) goto test;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if (read != buf1_len + buf2_len) {
 | 
	
		
			
				|  |  |            print_error(buf2, read);
 | 
	
	
		
			
				|  | @@ -3940,7 +3982,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          read += parse(buf3, buf3_len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if (parser->upgrade) goto test;
 | 
	
		
			
				|  |  | +        if (parser.upgrade) goto test;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if (read != buf1_len + buf2_len + buf3_len) {
 | 
	
		
			
				|  |  |            print_error(buf3, read);
 | 
	
	
		
			
				|  | @@ -3950,7 +3992,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
 | 
	
		
			
				|  |  |          parse(NULL, 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  test:
 | 
	
		
			
				|  |  | -        if (parser->upgrade) {
 | 
	
		
			
				|  |  | +        if (parser.upgrade) {
 | 
	
		
			
				|  |  |            upgrade_message_fix(total, read, 3, r1, r2, r3);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -3974,8 +4016,6 @@ test:
 | 
	
		
			
				|  |  |            fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
 | 
	
		
			
				|  |  |            goto error;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        parser_free();
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -4039,7 +4079,7 @@ test_message_pause (const struct message *msg)
 | 
	
		
			
				|  |  |      // completion callback.
 | 
	
		
			
				|  |  |      if (messages[0].message_complete_cb_called &&
 | 
	
		
			
				|  |  |          msg->upgrade &&
 | 
	
		
			
				|  |  | -        parser->upgrade) {
 | 
	
		
			
				|  |  | +        parser.upgrade) {
 | 
	
		
			
				|  |  |        messages[0].upgrade = buf + nread;
 | 
	
		
			
				|  |  |        goto test;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -4047,17 +4087,16 @@ test_message_pause (const struct message *msg)
 | 
	
		
			
				|  |  |      if (nread < buflen) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        // Not much do to if we failed a strict-mode check
 | 
	
		
			
				|  |  | -      if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
 | 
	
		
			
				|  |  | -        parser_free();
 | 
	
		
			
				|  |  | +      if (HTTP_PARSER_ERRNO(&parser) == HPE_STRICT) {
 | 
	
		
			
				|  |  |          return;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
 | 
	
		
			
				|  |  | +      assert (HTTP_PARSER_ERRNO(&parser) == HPE_PAUSED);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      buf += nread;
 | 
	
		
			
				|  |  |      buflen -= nread;
 | 
	
		
			
				|  |  | -    http_parser_pause(parser, 0);
 | 
	
		
			
				|  |  | +    http_parser_pause(&parser, 0);
 | 
	
		
			
				|  |  |    } while (buflen > 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    nread = parse_pause(NULL, 0);
 | 
	
	
		
			
				|  | @@ -4070,8 +4109,6 @@ test:
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if(!message_eq(0, 0, msg)) abort();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  parser_free();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Verify that body and next message won't be parsed in responses to CONNECT */
 | 
	
	
		
			
				|  | @@ -4091,14 +4128,11 @@ test_message_connect (const struct message *msg)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if(!message_eq(0, 1, msg)) abort();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  parser_free();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  main (void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -  parser = NULL;
 | 
	
		
			
				|  |  |    unsigned i, j, k;
 | 
	
		
			
				|  |  |    unsigned long version;
 | 
	
		
			
				|  |  |    unsigned major;
 | 
	
	
		
			
				|  | @@ -4117,6 +4151,7 @@ main (void)
 | 
	
		
			
				|  |  |    test_preserve_data();
 | 
	
		
			
				|  |  |    test_parse_url();
 | 
	
		
			
				|  |  |    test_method_str();
 | 
	
		
			
				|  |  | +  test_status_str();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    //// NREAD
 | 
	
		
			
				|  |  |    test_header_nread_value();
 | 
	
	
		
			
				|  | @@ -4149,6 +4184,13 @@ main (void)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    test_simple_type(
 | 
	
		
			
				|  |  |        "POST / HTTP/1.1\r\n"
 | 
	
		
			
				|  |  | +      "Content-Length:\r\n"  // empty
 | 
	
		
			
				|  |  | +      "\r\n",
 | 
	
		
			
				|  |  | +      HPE_INVALID_CONTENT_LENGTH,
 | 
	
		
			
				|  |  | +      HTTP_REQUEST);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  test_simple_type(
 | 
	
		
			
				|  |  | +      "POST / HTTP/1.1\r\n"
 | 
	
		
			
				|  |  |        "Content-Length:  42 \r\n"  // Note the surrounding whitespace.
 | 
	
		
			
				|  |  |        "\r\n",
 | 
	
		
			
				|  |  |        HPE_OK,
 | 
	
	
		
			
				|  | @@ -4168,6 +4210,20 @@ main (void)
 | 
	
		
			
				|  |  |        HPE_INVALID_CONTENT_LENGTH,
 | 
	
		
			
				|  |  |        HTTP_REQUEST);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  test_simple_type(
 | 
	
		
			
				|  |  | +      "POST / HTTP/1.1\r\n"
 | 
	
		
			
				|  |  | +      "Content-Length:  42\r\n"
 | 
	
		
			
				|  |  | +      " Hello world!\r\n",
 | 
	
		
			
				|  |  | +      HPE_INVALID_CONTENT_LENGTH,
 | 
	
		
			
				|  |  | +      HTTP_REQUEST);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  test_simple_type(
 | 
	
		
			
				|  |  | +      "POST / HTTP/1.1\r\n"
 | 
	
		
			
				|  |  | +      "Content-Length:  42\r\n"
 | 
	
		
			
				|  |  | +      " \r\n",
 | 
	
		
			
				|  |  | +      HPE_OK,
 | 
	
		
			
				|  |  | +      HTTP_REQUEST);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    //// RESPONSES
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    test_simple_type("HTP/1.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
 | 
	
	
		
			
				|  | @@ -4175,6 +4231,7 @@ main (void)
 | 
	
		
			
				|  |  |    test_simple_type("HTTP/11.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
 | 
	
		
			
				|  |  |    test_simple_type("HTTP/1.01 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
 | 
	
		
			
				|  |  |    test_simple_type("HTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
 | 
	
		
			
				|  |  | +  test_simple_type("\rHTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (i = 0; i < ARRAY_SIZE(responses); i++) {
 | 
	
		
			
				|  |  |      test_message(&responses[i]);
 | 
	
	
		
			
				|  | @@ -4252,11 +4309,16 @@ main (void)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /// REQUESTS
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  test_simple("GET / IHTTP/1.0\r\n\r\n", HPE_INVALID_CONSTANT);
 | 
	
		
			
				|  |  | +  test_simple("GET / ICE/1.0\r\n\r\n", HPE_INVALID_CONSTANT);
 | 
	
		
			
				|  |  |    test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
 | 
	
		
			
				|  |  |    test_simple("GET / HTTP/01.1\r\n\r\n", HPE_INVALID_VERSION);
 | 
	
		
			
				|  |  |    test_simple("GET / HTTP/11.1\r\n\r\n", HPE_INVALID_VERSION);
 | 
	
		
			
				|  |  |    test_simple("GET / HTTP/1.01\r\n\r\n", HPE_INVALID_VERSION);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  test_simple("GET / HTTP/1.0\r\nHello: w\1rld\r\n\r\n", HPE_INVALID_HEADER_TOKEN);
 | 
	
		
			
				|  |  | +  test_simple("GET / HTTP/1.0\r\nHello: woooo\2rld\r\n\r\n", HPE_INVALID_HEADER_TOKEN);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    // Extended characters - see nodejs/test/parallel/test-http-headers-obstext.js
 | 
	
		
			
				|  |  |    test_simple("GET / HTTP/1.1\r\n"
 | 
	
		
			
				|  |  |                "Test: Düsseldorf\r\n",
 | 
	
	
		
			
				|  | @@ -4339,9 +4401,9 @@ main (void)
 | 
	
		
			
				|  |  |                "\r\n",
 | 
	
		
			
				|  |  |                HPE_INVALID_HEADER_TOKEN);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  const char *dumbfuck2 =
 | 
	
		
			
				|  |  | +  const char *dumbluck2 =
 | 
	
		
			
				|  |  |      "GET / HTTP/1.1\r\n"
 | 
	
		
			
				|  |  | -    "X-SSL-Bullshit:   -----BEGIN CERTIFICATE-----\r\n"
 | 
	
		
			
				|  |  | +    "X-SSL-Nonsense:   -----BEGIN CERTIFICATE-----\r\n"
 | 
	
		
			
				|  |  |      "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
 | 
	
		
			
				|  |  |      "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
 | 
	
		
			
				|  |  |      "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
 | 
	
	
		
			
				|  | @@ -4374,7 +4436,7 @@ main (void)
 | 
	
		
			
				|  |  |      "\tRA==\r\n"
 | 
	
		
			
				|  |  |      "\t-----END CERTIFICATE-----\r\n"
 | 
	
		
			
				|  |  |      "\r\n";
 | 
	
		
			
				|  |  | -  test_simple(dumbfuck2, HPE_OK);
 | 
	
		
			
				|  |  | +  test_simple(dumbluck2, HPE_OK);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const char *corrupted_connection =
 | 
	
		
			
				|  |  |      "GET / HTTP/1.1\r\n"
 | 
	
	
		
			
				|  | @@ -4441,7 +4503,7 @@ main (void)
 | 
	
		
			
				|  |  |    printf("request scan 3/4      ");
 | 
	
		
			
				|  |  |    test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
 | 
	
		
			
				|  |  |             , &requests[CHUNKED_W_TRAILING_HEADERS]
 | 
	
		
			
				|  |  | -           , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
 | 
	
		
			
				|  |  | +           , &requests[CHUNKED_W_NONSENSE_AFTER_LENGTH]
 | 
	
		
			
				|  |  |             );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    printf("request scan 4/4      ");
 |