Upgrade http-parser
authorRyan Dahl <ry@tinyclouds.org>
Sat, 9 Jan 2010 09:52:49 +0000 (01:52 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Sat, 9 Jan 2010 09:52:49 +0000 (01:52 -0800)
deps/http_parser/LICENSE-MIT
deps/http_parser/README.md
deps/http_parser/http_parser.c
deps/http_parser/http_parser.h
deps/http_parser/test.c
src/node_http.cc
src/node_http.h

index cb938cd0899ab5db2384e25e4fca37a4dae0cee9..f30a31de94635399f42fd05f91f6ed3ff2f013d6 100644 (file)
@@ -1,4 +1,4 @@
-Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
+Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to
index bca5aeaa4345f73d173e042b30873263850acb8f..6684cfeff2817dab9b24a5eec05e0e37e3345e11 100644 (file)
@@ -29,10 +29,10 @@ Usage
 
 One `http_parser` object is used per TCP connection. Initialize the struct
 using `http_parser_init()` and set the callbacks. That might look something
-like this:
+like this for a request parser:
 
     http_parser *parser = malloc(sizeof(http_parser));
-    http_parser_init(parser);
+    http_parser_init(parser, HTTP_REQUEST);
     parser->on_path = my_path_callback;
     parser->on_header_field = my_header_field_callback;
     /* ... */
@@ -54,7 +54,7 @@ When data is received on the socket execute the parser and check for errors.
      * Note we pass the recved==0 to http_parse_requests to signal
      * that EOF has been recieved.
      */
-    nparsed = http_parse_requests(parser, buf, recved);
+    nparsed = http_parser_execute(parser, buf, recved);
 
     if (nparsed != recved) {
       /* Handle error. Usually just close the connection. */
@@ -63,7 +63,7 @@ When data is received on the socket execute the parser and check for errors.
 HTTP needs to know where the end of the stream is. For example, sometimes
 servers send responses without Content-Length and expect the client to
 consume input (for the body) until EOF. To tell http_parser about EOF, give
-`0` as the third parameter to `http_parse_requests()`. Callbacks and errors
+`0` as the third parameter to `http_parser_execute()`. Callbacks and errors
 can still be encountered during an EOF, so one must still be prepared
 to receive them.
 
@@ -85,7 +85,7 @@ parser, for example, would not want such a feature.
 Callbacks
 ---------
 
-During the `http_parse_requests()` call, the callbacks set in `http_parser`
+During the `http_parser_execute()` call, the callbacks set in `http_parser`
 will be executed. The parser maintains state and never looks behind, so
 buffering the data is not necessary. If you need to save certain data for
 later usage, you can do that from the callbacks.
index 9088af72c1c752249a7c237e9ac86ad80d4b095c..95afa1814296738930bc79486be447521040c33c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
+/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
  *
  * Some parts of this source file were taken from NGINX
  * (src/http/ngx_http_parser.c) copyright (C) 2002-2009 Igor Sysoev.
@@ -97,6 +97,7 @@ static inline int message_complete_callback (http_parser *parser)
   return parser->on_message_complete(parser);
 }
 
+#define PROXY_CONNECTION "proxy-connection"
 #define CONNECTION "connection"
 #define CONTENT_LENGTH "content-length"
 #define TRANSFER_ENCODING "transfer-encoding"
@@ -218,6 +219,7 @@ enum header_states
   , h_CON
 
   , h_matching_connection
+  , h_matching_proxy_connection
   , h_matching_content_length
   , h_matching_transfer_encoding
 
@@ -245,6 +247,8 @@ enum flags
 #define LF '\n'
 #define LOWER(c) (unsigned char)(c | 0x20)
 
+#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
+
 #if HTTP_PARSER_STRICT
 # define STRICT_CHECK(cond) if (cond) goto error
 # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
@@ -253,8 +257,9 @@ enum flags
 # define NEW_MESSAGE() start_state
 #endif
 
-static inline
-size_t parse (http_parser *parser, const char *data, size_t len, int start_state)
+size_t http_parser_execute (http_parser *parser,
+                            const char *data,
+                            size_t len)
 {
   char c, ch;
   const char *p, *pe;
@@ -950,6 +955,10 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state
             header_state = h_C;
             break;
 
+          case 'p':
+            header_state = h_matching_proxy_connection;
+            break;
+
           case 't':
             header_state = h_matching_transfer_encoding;
             break;
@@ -1007,6 +1016,18 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state
               }
               break;
 
+            /* proxy-connection */
+
+            case h_matching_proxy_connection:
+              index++;
+              if (index > sizeof(PROXY_CONNECTION)-1
+                  || c != PROXY_CONNECTION[index]) {
+                header_state = h_general;
+              } else if (index == sizeof(PROXY_CONNECTION)-2) {
+                header_state = h_connection;
+              }
+              break;
+
             /* content-length */
 
             case h_matching_content_length:
@@ -1256,7 +1277,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state
             /* Content-Length header given and non-zero */
             state = s_body_identity;
           } else {
-            if (start_state == s_start_req || http_should_keep_alive(parser)) {
+            if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
               /* Assume content-length 0 - read the next */
               CALLBACK2(message_complete);
               state = NEW_MESSAGE();
@@ -1408,22 +1429,6 @@ error:
 }
 
 
-size_t
-http_parse_requests (http_parser *parser, const char *data, size_t len)
-{
-  if (!parser->state) parser->state = s_start_req;
-  return parse(parser, data, len, s_start_req);
-}
-
-
-size_t
-http_parse_responses (http_parser *parser, const char *data, size_t len)
-{
-  if (!parser->state) parser->state = s_start_res;
-  return parse(parser, data, len, s_start_res);
-}
-
-
 int
 http_should_keep_alive (http_parser *parser)
 {
@@ -1446,9 +1451,10 @@ http_should_keep_alive (http_parser *parser)
 
 
 void
-http_parser_init (http_parser *parser)
+http_parser_init (http_parser *parser, enum http_parser_type t)
 {
-  parser->state = 0;
+  parser->type = t;
+  parser->state = (t == HTTP_REQUEST ? s_start_req : s_start_res);
   parser->on_message_begin = NULL;
   parser->on_path = NULL;
   parser->on_query_string = NULL;
index 5855e89405b2a84c9c6b181c93632b83b53d859d..a1439ea3647ff21628b1d9f58034286f4108536e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
+/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -74,8 +74,11 @@ enum http_method
   , HTTP_UNLOCK    = 0x4000
   };
 
+enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE };
+
 struct http_parser {
   /** PRIVATE **/
+  enum http_parser_type type;
   unsigned short state;
   unsigned short header_state;
   size_t index;
@@ -125,9 +128,8 @@ struct http_parser {
   http_cb      on_message_complete;
 };
 
-void http_parser_init(http_parser *parser);
-size_t http_parse_requests(http_parser *parser, const char *data, size_t len);
-size_t http_parse_responses(http_parser *parser, const char *data, size_t len);
+void http_parser_init(http_parser *parser, enum http_parser_type type);
+size_t http_parser_execute(http_parser *parser, const char *data, size_t len);
 /* Call this in the on_headers_complete or on_message_complete callback to
  * determine if this will be the last message on the connection.
  * If you are the server, respond with the "Connection: close" header
index 5f4c418f09c27e27cc329c2a86a5f299e27d1a27..07f0f8119e64a6a212a94519ffc493b0d1a65705 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
+/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
 #define MAX_HEADERS 10
 #define MAX_ELEMENT_SIZE 500
 
-enum message_type { REQUEST, RESPONSE };
-
 static http_parser *parser;
 
 struct message {
   const char *name; // for debugging purposes
   const char *raw;
-  enum message_type type;
+  enum http_parser_type type;
   enum http_method method;
   int status_code;
   char request_path[MAX_ELEMENT_SIZE];
@@ -60,17 +58,16 @@ struct message {
   int message_begin_cb_called;
   int headers_complete_cb_called;
   int message_complete_cb_called;
-  int message_complete_on_eof;
+  int eof_indicates_message_end;
 };
 
 static int currently_parsing_eof;
 
-inline size_t parse (enum message_type t, const char *buf, size_t len)
+inline size_t parse (const char *buf, size_t len)
 {
   size_t nparsed;
   currently_parsing_eof = (len == 0);
-  nparsed = (t == REQUEST ? http_parse_requests(parser, buf, len)
-                          : http_parse_responses(parser, buf, len));
+  nparsed = http_parser_execute(parser, buf, len);
   return nparsed;
 }
 
@@ -81,14 +78,14 @@ static int num_messages;
 const struct message requests[] =
 #define CURL_GET 0
 { {.name= "curl get"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /test HTTP/1.1\r\n"
          "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n"
          "Host: 0.0.0.0=5000\r\n"
          "Accept: */*\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -107,7 +104,7 @@ const struct message requests[] =
 
 #define FIREFOX_GET 1
 , {.name= "firefox get"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /favicon.ico HTTP/1.1\r\n"
          "Host: 0.0.0.0=5000\r\n"
          "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
@@ -119,7 +116,7 @@ const struct message requests[] =
          "Connection: keep-alive\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -143,12 +140,12 @@ const struct message requests[] =
 
 #define DUMBFUCK 2
 , {.name= "dumbfuck"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
          "aaaaaaaaaaaaa:++++++++++\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -165,11 +162,11 @@ const struct message requests[] =
 
 #define FRAGMENT_IN_URI 3
 , {.name= "fragment in url"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -184,11 +181,11 @@ const struct message requests[] =
 
 #define GET_NO_HEADERS_NO_BODY 4
 , {.name= "get no headers no body"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE /* would need Connection: close */
+  ,.eof_indicates_message_end= FALSE /* would need Connection: close */
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -202,12 +199,12 @@ const struct message requests[] =
 
 #define GET_ONE_HEADER_NO_BODY 5
 , {.name= "get one header no body"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n"
          "Accept: */*\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE /* would need Connection: close */
+  ,.eof_indicates_message_end= FALSE /* would need Connection: close */
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -224,13 +221,13 @@ const struct message requests[] =
 
 #define GET_FUNKY_CONTENT_LENGTH 6
 , {.name= "get funky content length body hello"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
          "conTENT-Length: 5\r\n"
          "\r\n"
          "HELLO"
   ,.should_keep_alive= FALSE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 0
   ,.method= HTTP_GET
@@ -247,7 +244,7 @@ const struct message requests[] =
 
 #define POST_IDENTITY_BODY_WORLD 7
 , {.name= "post identity body world"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
          "Accept: */*\r\n"
          "Transfer-Encoding: identity\r\n"
@@ -255,7 +252,7 @@ const struct message requests[] =
          "\r\n"
          "World"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_POST
@@ -274,7 +271,7 @@ const struct message requests[] =
 
 #define POST_CHUNKED_ALL_YOUR_BASE 8
 , {.name= "post - chunked body: all your base are belong to us"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n"
          "Transfer-Encoding: chunked\r\n"
          "\r\n"
@@ -282,7 +279,7 @@ const struct message requests[] =
          "0\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_POST
@@ -299,7 +296,7 @@ const struct message requests[] =
 
 #define TWO_CHUNKS_MULT_ZERO_END 9
 , {.name= "two chunks ; triple zero ending"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
          "Transfer-Encoding: chunked\r\n"
          "\r\n"
@@ -308,7 +305,7 @@ const struct message requests[] =
          "000\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_POST
@@ -325,7 +322,7 @@ const struct message requests[] =
 
 #define CHUNKED_W_TRAILING_HEADERS 10
 , {.name= "chunked with trailing headers. blech."
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n"
          "Transfer-Encoding: chunked\r\n"
          "\r\n"
@@ -336,7 +333,7 @@ const struct message requests[] =
          "Content-Type: text/plain\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_POST
@@ -355,7 +352,7 @@ const struct message requests[] =
 
 #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
 , {.name= "with bullshit after the length"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
          "Transfer-Encoding: chunked\r\n"
          "\r\n"
@@ -364,7 +361,7 @@ const struct message requests[] =
          "0\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_POST
@@ -381,10 +378,10 @@ const struct message requests[] =
 
 #define WITH_QUOTES 12
 , {.name= "with quotes"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.method= HTTP_GET
@@ -400,17 +397,17 @@ const struct message requests[] =
 #define APACHEBENCH_GET 13
 /* The server receiving this request SHOULD NOT wait for EOF
  * to know that content-length == 0.
- * How to represent this in a unit test? message_complete_on_eof
+ * How to represent this in a unit test? eof_indicates_message_end
  * Compare with NO_CONTENT_LENGTH_RESPONSE.
  */
 , {.name = "apachebench get"
-  ,.type= REQUEST
+  ,.type= HTTP_REQUEST
   ,.raw= "GET /test HTTP/1.0\r\n"
          "Host: 0.0.0.0:5000\r\n"
          "User-Agent: ApacheBench/2.3\r\n"
          "Accept: */*\r\n\r\n"
   ,.should_keep_alive= FALSE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 0
   ,.method= HTTP_GET
@@ -433,7 +430,7 @@ const struct message requests[] =
 const struct message responses[] =
 #define GOOGLE_301 0
 { {.name= "google 301"
-  ,.type= RESPONSE
+  ,.type= HTTP_RESPONSE
   ,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
          "Location: http://www.google.com/\r\n"
          "Content-Type: text/html; charset=UTF-8\r\n"
@@ -450,7 +447,7 @@ const struct message responses[] =
          "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
          "</BODY></HTML>\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.status_code= 301
@@ -479,7 +476,7 @@ const struct message responses[] =
  * Compare with APACHEBENCH_GET
  */
 , {.name= "no content-length response"
-  ,.type= RESPONSE
+  ,.type= HTTP_RESPONSE
   ,.raw= "HTTP/1.1 200 OK\r\n"
          "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
          "Server: Apache\r\n"
@@ -497,7 +494,7 @@ const struct message responses[] =
          "  </SOAP-ENV:Body>\n"
          "</SOAP-ENV:Envelope>"
   ,.should_keep_alive= FALSE
-  ,.message_complete_on_eof= TRUE
+  ,.eof_indicates_message_end= TRUE
   ,.http_major= 1
   ,.http_minor= 1
   ,.status_code= 200
@@ -522,10 +519,10 @@ const struct message responses[] =
 
 #define NO_HEADERS_NO_BODY_404 2
 , {.name= "404 no headers no body"
-  ,.type= RESPONSE
+  ,.type= HTTP_RESPONSE
   ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.status_code= 404
@@ -536,10 +533,10 @@ const struct message responses[] =
 
 #define NO_REASON_PHRASE 3
 , {.name= "301 no response phrase"
-  ,.type= RESPONSE
+  ,.type= HTTP_RESPONSE
   ,.raw= "HTTP/1.1 301\r\n\r\n"
   ,.should_keep_alive = TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.status_code= 301
@@ -550,7 +547,7 @@ const struct message responses[] =
 
 #define TRAILING_SPACE_ON_CHUNKED_BODY 4
 , {.name="200 trailing space on chunked body"
-  ,.type= RESPONSE
+  ,.type= HTTP_RESPONSE
   ,.raw= "HTTP/1.1 200 OK\r\n"
          "Content-Type: text/plain\r\n"
          "Transfer-Encoding: chunked\r\n"
@@ -564,7 +561,7 @@ const struct message responses[] =
          "0  \r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
-  ,.message_complete_on_eof= FALSE
+  ,.eof_indicates_message_end= FALSE
   ,.http_major= 1
   ,.http_minor= 1
   ,.status_code= 200
@@ -581,14 +578,14 @@ const struct message responses[] =
 
 #define NO_CARRIAGE_RET 5
 , {.name="no carriage ret"
-  ,.type= RESPONSE
+  ,.type= HTTP_RESPONSE
   ,.raw= "HTTP/1.1 200 OK\n"
          "Content-Type: text/html; charset=utf-8\n"
          "Connection: close\n"
          "\n"
          "these headers are from http://news.ycombinator.com/"
   ,.should_keep_alive= FALSE
-  ,.message_complete_on_eof= TRUE
+  ,.eof_indicates_message_end= TRUE
   ,.http_major= 1
   ,.http_minor= 1
   ,.status_code= 200
@@ -600,6 +597,31 @@ const struct message responses[] =
   ,.body= "these headers are from http://news.ycombinator.com/"
   }
 
+#define PROXY_CONNECTION 6
+, {.name="proxy connection"
+  ,.type= HTTP_RESPONSE
+  ,.raw= "HTTP/1.1 200 OK\r\n"
+         "Content-Type: text/html; charset=UTF-8\r\n"
+         "Content-Length: 11\r\n"
+         "Proxy-Connection: close\r\n"
+         "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n"
+         "\r\n"
+         "hello world"
+  ,.should_keep_alive= FALSE
+  ,.eof_indicates_message_end= FALSE
+  ,.http_major= 1
+  ,.http_minor= 1
+  ,.status_code= 200
+  ,.num_headers= 4
+  ,.headers=
+    { {"Content-Type", "text/html; charset=UTF-8" }
+    , {"Content-Length", "11" }
+    , {"Proxy-Connection", "close" }
+    , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"}
+    }
+  ,.body= "hello world"
+  }
+
 , {.name= NULL } /* sentinel */
 };
 
@@ -708,14 +730,14 @@ message_complete_cb (http_parser *p)
   }
   messages[num_messages].message_complete_cb_called = TRUE;
 
-  messages[num_messages].message_complete_on_eof = currently_parsing_eof;
+  messages[num_messages].eof_indicates_message_end = currently_parsing_eof;
 
   num_messages++;
   return 0;
 }
 
 void
-parser_init ()
+parser_init (enum http_parser_type type)
 {
   num_messages = 0;
 
@@ -723,7 +745,7 @@ parser_init ()
 
   parser = malloc(sizeof(http_parser));
 
-  http_parser_init(parser);
+  http_parser_init(parser, type);
 
   memset(&messages, 0, sizeof messages);
 
@@ -791,14 +813,14 @@ message_eq (int index, const struct message *expected)
   MESSAGE_CHECK_NUM_EQ(expected, m, http_major);
   MESSAGE_CHECK_NUM_EQ(expected, m, http_minor);
 
-  if (expected->type == REQUEST) {
+  if (expected->type == HTTP_REQUEST) {
     MESSAGE_CHECK_NUM_EQ(expected, m, method);
   } else {
     MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
   }
 
   MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
-  MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
+  MESSAGE_CHECK_NUM_EQ(expected, m, eof_indicates_message_end);
 
   assert(m->message_begin_cb_called);
   assert(m->headers_complete_cb_called);
@@ -869,17 +891,17 @@ print_error (const char *raw, size_t error_location)
 void
 test_message (const struct message *message)
 {
-  parser_init();
+  parser_init(message->type);
 
   size_t read;
 
-  read = parse(message->type, message->raw, strlen(message->raw));
+  read = parse(message->raw, strlen(message->raw));
   if (read != strlen(message->raw)) {
     print_error(message->raw, read);
     exit(1);
   }
 
-  read = parse(message->type, NULL, 0);
+  read = parse(NULL, 0);
   if (read != 0) {
     print_error(message->raw, read);
     exit(1);
@@ -898,13 +920,13 @@ test_message (const struct message *message)
 void
 test_error (const char *buf)
 {
-  parser_init();
+  parser_init(HTTP_REQUEST);
 
   size_t parsed;
 
-  parsed = parse(REQUEST, buf, strlen(buf));
+  parsed = parse(buf, strlen(buf));
   if (parsed != strlen(buf)) goto out;
-  parsed = parse(REQUEST, NULL, 0);
+  parsed = parse(NULL, 0);
   if (parsed != 0) goto out;
 
   fprintf(stderr, "\n*** Error expected but none found ***\n\n%s", buf);
@@ -929,17 +951,17 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
   strcat(total, r2->raw);
   strcat(total, r3->raw);
 
-  parser_init();
+  parser_init(r1->type);
 
   size_t read;
 
-  read = parse(r1->type, total, strlen(total));
+  read = parse(total, strlen(total));
   if (read != strlen(total)) {
     print_error(total, read);
     exit(1);
   }
 
-  read = parse(REQUEST, NULL, 0);
+  read = parse(NULL, 0);
   if (read != 0) {
     print_error(total, read);
     exit(1);
@@ -992,7 +1014,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
       }
       ops += 1;
 
-      parser_init();
+      parser_init(r1->type);
 
       buf1_len = i;
       strncpy(buf1, total, buf1_len);
@@ -1006,25 +1028,25 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
       strncpy(buf3, total+j, buf3_len);
       buf3[buf3_len] = 0;
 
-      read = parse(r1->type, buf1, buf1_len);
+      read = parse(buf1, buf1_len);
       if (read != buf1_len) {
         print_error(buf1, read);
         goto error;
       }
 
-      read = parse(r1->type, buf2, buf2_len);
+      read = parse(buf2, buf2_len);
       if (read != buf2_len) {
         print_error(buf2, read);
         goto error;
       }
 
-      read = parse(r1->type, buf3, buf3_len);
+      read = parse(buf3, buf3_len);
       if (read != buf3_len) {
         print_error(buf3, read);
         goto error;
       }
 
-      parse(r1->type, NULL, 0);
+      parse(NULL, 0);
 
       if (3 != num_messages) {
         fprintf(stderr, "\n\nParser didn't see 3 messages only %d\n", num_messages);
index 230b27200c7053c82e658d0fbacbb80a1ce83b4f..2ba9a08fc2a9a7734c2d18a71fd7f22db15067f3 100644 (file)
@@ -127,13 +127,9 @@ HTTPConnection::OnReceive (const void *buf, size_t len)
   HandleScope scope;
 
   assert(refs_);
-  size_t nparsed; 
+  size_t nparsed;
 
-  if (type_ == HTTP_REQUEST) {
-    nparsed = http_parse_requests(&parser_, static_cast<const char*>(buf), len);
-  } else {
-    nparsed = http_parse_responses(&parser_, static_cast<const char*>(buf), len);
-  }
+  nparsed = http_parser_execute(&parser_, static_cast<const char*>(buf), len);
 
   if (nparsed != len) {
     ForceClose();
@@ -145,11 +141,8 @@ HTTPConnection::OnEOF ()
 {
   HandleScope scope;
   assert(refs_);
-  if (type_ == HTTP_REQUEST) {
-    http_parse_requests(&parser_, NULL, 0);
-  } else {
-    http_parse_responses(&parser_, NULL, 0);
-  }
+  size_t nparsed;
+  nparsed = http_parser_execute(&parser_, NULL, 0);
   Emit(eof_symbol, 0, NULL);
 }
 
index 1e36df0fab9820e88b78b2e3bbc028f355da8e9e..ad368b3a1faafdae7368a8541717523270bbbd49 100644 (file)
@@ -7,8 +7,6 @@
 
 namespace node {
 
-enum http_connection_type { HTTP_RESPONSE, HTTP_REQUEST };
-
 class HTTPConnection : public Connection {
 public:
   static void Initialize (v8::Handle<v8::Object> target);
@@ -21,7 +19,7 @@ protected:
   static v8::Handle<v8::Value> NewServer (const v8::Arguments& args);
   static v8::Handle<v8::Value> ResetParser(const v8::Arguments& args);
 
-  HTTPConnection (enum http_connection_type t)
+  HTTPConnection (enum http_parser_type t)
     : Connection()
   {
     type_ = t;
@@ -29,7 +27,7 @@ protected:
   }
 
   void ResetParser() {
-    http_parser_init (&parser_);
+    http_parser_init (&parser_, type_);
     parser_.on_message_begin    = on_message_begin;
     parser_.on_url              = on_url;
     parser_.on_path             = on_path;
@@ -57,10 +55,8 @@ protected:
   static int on_body (http_parser *parser, const char *buf, size_t len);
   static int on_message_complete (http_parser *parser);
 
+  enum http_parser_type type_;
   http_parser parser_;
-  enum http_connection_type type_; // should probably use subclass
-                                   // but going to refactor this all soon
-                                   // so won't worry about it.
   friend class HTTPServer;
 };