typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
-typedef struct http_parser_result http_parser_result;
/* Callbacks should return non-zero to indicate an error. The parser will
/* Request Methods */
+#define HTTP_METHOD_MAP(XX) \
+ XX(0, DELETE, DELETE) \
+ XX(1, GET, GET) \
+ XX(2, HEAD, HEAD) \
+ XX(3, POST, POST) \
+ XX(4, PUT, PUT) \
+ /* pathological */ \
+ XX(5, CONNECT, CONNECT) \
+ XX(6, OPTIONS, OPTIONS) \
+ XX(7, TRACE, TRACE) \
+ /* webdav */ \
+ XX(8, COPY, COPY) \
+ XX(9, LOCK, LOCK) \
+ XX(10, MKCOL, MKCOL) \
+ XX(11, MOVE, MOVE) \
+ XX(12, PROPFIND, PROPFIND) \
+ XX(13, PROPPATCH, PROPPATCH) \
+ XX(14, SEARCH, SEARCH) \
+ XX(15, UNLOCK, UNLOCK) \
+ /* subversion */ \
+ XX(16, REPORT, REPORT) \
+ XX(17, MKACTIVITY, MKACTIVITY) \
+ XX(18, CHECKOUT, CHECKOUT) \
+ XX(19, MERGE, MERGE) \
+ /* upnp */ \
+ XX(20, MSEARCH, M-SEARCH) \
+ XX(21, NOTIFY, NOTIFY) \
+ XX(22, SUBSCRIBE, SUBSCRIBE) \
+ XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
+ /* RFC-5789 */ \
+ XX(24, PATCH, PATCH) \
+ XX(25, PURGE, PURGE) \
+
enum http_method
- { HTTP_DELETE = 0
- , HTTP_GET
- , HTTP_HEAD
- , HTTP_POST
- , HTTP_PUT
- /* pathological */
- , HTTP_CONNECT
- , HTTP_OPTIONS
- , HTTP_TRACE
- /* webdav */
- , HTTP_COPY
- , HTTP_LOCK
- , HTTP_MKCOL
- , HTTP_MOVE
- , HTTP_PROPFIND
- , HTTP_PROPPATCH
- , HTTP_UNLOCK
- /* subversion */
- , HTTP_REPORT
- , HTTP_MKACTIVITY
- , HTTP_CHECKOUT
- , HTTP_MERGE
- /* upnp */
- , HTTP_MSEARCH
- , HTTP_NOTIFY
- , HTTP_SUBSCRIBE
- , HTTP_UNSUBSCRIBE
- /* RFC-5789 */
- , HTTP_PATCH
- , HTTP_PURGE
+ {
+#define XX(num, name, string) HTTP_##name = num,
+ HTTP_METHOD_MAP(XX)
+#undef XX
};
,.body= ""
}
-#define LINE_FOLDING_IN_HEADER 20
+#define LINE_FOLDING_IN_HEADER 21
, {.name= "line folding in header value"
,.type= HTTP_REQUEST
,.raw= "GET / HTTP/1.1\r\n"
}
-#define QUERY_TERMINATED_HOST 21
+#define QUERY_TERMINATED_HOST 22
, {.name= "host terminated by a query string"
,.type= HTTP_REQUEST
,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
,.body= ""
}
-#define QUERY_TERMINATED_HOSTPORT 22
+#define QUERY_TERMINATED_HOSTPORT 23
, {.name= "host:port terminated by a query string"
,.type= HTTP_REQUEST
,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
,.body= ""
}
-#define SPACE_TERMINATED_HOSTPORT 23
+#define SPACE_TERMINATED_HOSTPORT 24
, {.name= "host:port terminated by a space"
,.type= HTTP_REQUEST
,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
,.body= ""
}
-#define PATCH_REQ 24
+#define PATCH_REQ 25
, {.name = "PATCH request"
,.type= HTTP_REQUEST
,.raw= "PATCH /file.txt HTTP/1.1\r\n"
,.body= "cccccccccc"
}
-#define CONNECT_CAPS_REQUEST 25
+#define CONNECT_CAPS_REQUEST 26
, {.name = "connect caps request"
,.type= HTTP_REQUEST
,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
}
#if !HTTP_PARSER_STRICT
-#define UTF8_PATH_REQ 26
+#define UTF8_PATH_REQ 27
, {.name= "utf-8 path request"
,.type= HTTP_REQUEST
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
,.body= ""
}
-#define HOSTNAME_UNDERSCORE 27
+#define HOSTNAME_UNDERSCORE 28
, {.name = "hostname underscore"
,.type= HTTP_REQUEST
,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
#endif /* !HTTP_PARSER_STRICT */
/* see https://github.com/ry/http-parser/issues/47 */
-#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 28
+#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
, {.name = "eat CRLF between requests, no \"Connection: close\" header"
,.raw= "POST / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
}
/* see https://github.com/ry/http-parser/issues/47 */
-#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 29
+#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
, {.name = "eat CRLF between requests even if \"Connection: close\" is set"
,.raw= "POST / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
,.body= "q=42"
}
-#define PURGE_REQ 30
+#define PURGE_REQ 31
, {.name = "PURGE request"
,.type= HTTP_REQUEST
,.raw= "PURGE /file.txt HTTP/1.1\r\n"
,.body= ""
}
+#define SEARCH_REQ 32
+, {.name = "SEARCH request"
+ ,.type= HTTP_REQUEST
+ ,.raw= "SEARCH / HTTP/1.1\r\n"
+ "Host: www.example.com\r\n"
+ "\r\n"
+ ,.should_keep_alive= TRUE
+ ,.message_complete_on_eof= FALSE
+ ,.http_major= 1
+ ,.http_minor= 1
+ ,.method= HTTP_SEARCH
+ ,.query_string= ""
+ ,.fragment= ""
+ ,.request_path= "/"
+ ,.request_url= "/"
+ ,.num_headers= 1
+ ,.headers= { { "Host", "www.example.com" } }
+ ,.body= ""
+ }
+
, {.name= NULL } /* sentinel */
};
"value in both on_message_complete and on_headers_complete "
"but it doesn't! ***\n\n");
assert(0);
- exit(1);
+ abort();
}
messages[num_messages].message_complete_cb_called = TRUE;
{
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
- exit(1);
+ abort();
}
int
{
if (p || buf || len) { } // gcc
fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
- exit(1);
+ abort();
}
int
{
if (p || buf || len) { } // gcc
fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
- exit(1);
+ abort();
}
int
{
if (p || buf || len) { } // gcc
fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
- exit(1);
+ abort();
}
int
{
if (p || buf || len) { } // gcc
fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
- exit(1);
+ abort();
}
int
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
"parser ***\n\n");
- exit(1);
+ abort();
}
int
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_message_complete() called on paused "
"parser ***\n\n");
- exit(1);
+ abort();
}
static http_parser_settings settings_dontcall =
if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
m->request_url);
- exit(1);
+ abort();
}
m->port = (u.field_set & (1 << UF_PORT)) ?
/* Check the portion of the response after its specified upgrade */
if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
- exit(1);
+ abort();
}
/* Fix up the response so that message_eq() will verify the beginning
va_end(ap);
printf("\n\n*** Error: expected a message with upgrade ***\n");
- exit(1);
+ abort();
}
static void
http_parser_init(&parser, HTTP_REQUEST);
if (parser.data != my_data) {
printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
- exit(1);
+ abort();
}
}
if (rv != 0) {
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
"unexpected rv %d ***\n\n", test->url, test->name, rv);
- exit(1);
+ abort();
}
if (memcmp(&u, &test->u, sizeof(u)) != 0) {
printf("result http_parser_url:\n");
dump_url(test->url, &u);
- exit(1);
+ abort();
}
} else {
/* test->rv != 0 */
if (rv == 0) {
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
"unexpected rv %d ***\n\n", test->url, test->name, rv);
- exit(1);
+ abort();
}
}
}
if (read != msg1len) {
print_error(msg1, read);
- exit(1);
+ abort();
}
}
if (read != msg2len) {
print_error(msg2, read);
- exit(1);
+ abort();
}
read = parse(NULL, 0);
if (read != 0) {
print_error(message->raw, read);
- exit(1);
+ abort();
}
test:
if (num_messages != 1) {
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
- exit(1);
+ abort();
}
- if(!message_eq(0, message)) exit(1);
+ if(!message_eq(0, message)) abort();
parser_free();
}
read = parse_count_body(message->raw + i, toread);
if (read != toread) {
print_error(message->raw, read);
- exit(1);
+ abort();
}
}
read = parse_count_body(NULL, 0);
if (read != 0) {
print_error(message->raw, read);
- exit(1);
+ abort();
}
if (num_messages != 1) {
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
- exit(1);
+ abort();
}
- if(!message_eq(0, message)) exit(1);
+ if(!message_eq(0, message)) abort();
parser_free();
}
#endif
fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
http_errno_name(err_expected), http_errno_name(err), buf);
- exit(1);
+ abort();
}
}
}
fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
- exit(1);
+ abort();
}
static void
"\n*** error in test_no_overflow_long_body %s of length %zu ***\n",
req ? "REQUEST" : "RESPONSE",
length);
- exit(1);
+ abort();
}
void
if (read != strlen(total)) {
print_error(total, read);
- exit(1);
+ abort();
}
read = parse(NULL, 0);
if (read != 0) {
print_error(total, read);
- exit(1);
+ abort();
}
test:
if (message_count != num_messages) {
fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
- exit(1);
+ abort();
}
- if (!message_eq(0, r1)) exit(1);
- if (message_count > 1 && !message_eq(1, r2)) exit(1);
- if (message_count > 2 && !message_eq(2, r3)) exit(1);
+ if (!message_eq(0, r1)) abort();
+ if (message_count > 1 && !message_eq(1, r2)) abort();
+ if (message_count > 2 && !message_eq(2, r3)) abort();
parser_free();
}
fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
- exit(1);
+ abort();
}
// user required to free the result
test:
if (num_messages != 1) {
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
- exit(1);
+ abort();
}
- if(!message_eq(0, msg)) exit(1);
+ if(!message_eq(0, msg)) abort();
parser_free();
}