Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/http_parser/http_parser.c')
-rw-r--r--deps/http_parser/http_parser.c334
1 files changed, 239 insertions, 95 deletions
diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c
index 1453d411b0c..e905747a320 100644
--- a/deps/http_parser/http_parser.c
+++ b/deps/http_parser/http_parser.c
@@ -31,10 +31,27 @@
#endif
+#if HTTP_PARSER_DEBUG
+#define SET_ERRNO(e) \
+do { \
+ parser->http_errno = (e); \
+ parser->error_lineno = __LINE__; \
+} while (0)
+#else
+#define SET_ERRNO(e) \
+do { \
+ parser->http_errno = (e); \
+} while(0)
+#endif
+
+
#define CALLBACK2(FOR) \
do { \
if (settings->on_##FOR) { \
- if (0 != settings->on_##FOR(parser)) return (p - data); \
+ if (0 != settings->on_##FOR(parser)) { \
+ SET_ERRNO(HPE_CB_##FOR); \
+ return (p - data); \
+ } \
} \
} while (0)
@@ -44,7 +61,7 @@ do { \
FOR##_mark = p; \
} while (0)
-#define CALLBACK_NOCLEAR(FOR) \
+#define CALLBACK(FOR) \
do { \
if (FOR##_mark) { \
if (settings->on_##FOR) { \
@@ -52,20 +69,15 @@ do { \
FOR##_mark, \
p - FOR##_mark)) \
{ \
+ SET_ERRNO(HPE_CB_##FOR); \
return (p - data); \
} \
} \
+ FOR##_mark = NULL; \
} \
} while (0)
-#define CALLBACK(FOR) \
-do { \
- CALLBACK_NOCLEAR(FOR); \
- FOR##_mark = NULL; \
-} while (0)
-
-
#define PROXY_CONNECTION "proxy-connection"
#define CONNECTION "connection"
#define CONTENT_LENGTH "content-length"
@@ -241,6 +253,7 @@ enum state
, s_header_field
, s_header_value_start
, s_header_value
+ , s_header_value_lws
, s_header_almost_done
@@ -299,7 +312,7 @@ enum header_states
#define LF '\n'
#define LOWER(c) (unsigned char)(c | 0x20)
#define TOKEN(c) (tokens[(unsigned char)c])
-#define IS_ALPHA(c) ((c) >= 'a' && (c) <= 'z')
+#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
@@ -318,7 +331,13 @@ enum header_states
#if HTTP_PARSER_STRICT
-# define STRICT_CHECK(cond) if (cond) goto error
+# define STRICT_CHECK(cond) \
+do { \
+ if (cond) { \
+ SET_ERRNO(HPE_STRICT); \
+ goto error; \
+ } \
+} while (0)
# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
#else
# define STRICT_CHECK(cond)
@@ -326,20 +345,39 @@ enum header_states
#endif
+/* Map errno values to strings for human-readable output */
+#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
+static struct {
+ const char *name;
+ const char *description;
+} http_strerror_tab[] = {
+ HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
+};
+#undef HTTP_STRERROR_GEN
+
+
size_t http_parser_execute (http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len)
{
char c, ch;
+ int8_t unhex_val;
const char *p = data, *pe;
int64_t to_read;
-
- enum state state = (enum state) parser->state;
- enum header_states header_state = (enum header_states) parser->header_state;
+ enum state state;
+ enum header_states header_state;
uint64_t index = parser->index;
uint64_t nread = parser->nread;
+ /* We're in an error state. Don't bother doing anything. */
+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
+ return 0;
+ }
+
+ state = (enum state) parser->state;
+ header_state = (enum header_states) parser->header_state;
+
if (len == 0) {
switch (state) {
case s_body_identity_eof:
@@ -353,7 +391,8 @@ size_t http_parser_execute (http_parser *parser,
return 0;
default:
- return 1; // error
+ SET_ERRNO(HPE_INVALID_EOF_STATE);
+ return 1;
}
}
@@ -362,21 +401,12 @@ size_t http_parser_execute (http_parser *parser,
separated. */
const char *header_field_mark = 0;
const char *header_value_mark = 0;
- const char *fragment_mark = 0;
- const char *query_string_mark = 0;
- const char *path_mark = 0;
const char *url_mark = 0;
if (state == s_header_field)
header_field_mark = data;
if (state == s_header_value)
header_value_mark = data;
- if (state == s_req_fragment)
- fragment_mark = data;
- if (state == s_req_query_string)
- query_string_mark = data;
- if (state == s_req_path)
- path_mark = data;
if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
|| state == s_req_schema_slash_slash || state == s_req_port
|| state == s_req_query_string_start || state == s_req_query_string
@@ -390,7 +420,10 @@ size_t http_parser_execute (http_parser *parser,
if (PARSING_HEADER(state)) {
++nread;
/* Buffer overflow attack */
- if (nread > HTTP_MAX_HEADER_SIZE) goto error;
+ if (nread > HTTP_MAX_HEADER_SIZE) {
+ SET_ERRNO(HPE_HEADER_OVERFLOW);
+ goto error;
+ }
}
switch (state) {
@@ -399,6 +432,7 @@ size_t http_parser_execute (http_parser *parser,
/* this state is used after a 'Connection: close' message
* the parser will error out if it reads another message
*/
+ SET_ERRNO(HPE_CLOSED_CONNECTION);
goto error;
case s_start_req_or_res:
@@ -424,7 +458,11 @@ size_t http_parser_execute (http_parser *parser,
parser->type = HTTP_RESPONSE;
state = s_res_HT;
} else {
- if (ch != 'E') goto error;
+ if (ch != 'E') {
+ SET_ERRNO(HPE_INVALID_CONSTANT);
+ goto error;
+ }
+
parser->type = HTTP_REQUEST;
parser->method = HTTP_HEAD;
index = 2;
@@ -449,6 +487,7 @@ size_t http_parser_execute (http_parser *parser,
break;
default:
+ SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
break;
@@ -475,7 +514,11 @@ size_t http_parser_execute (http_parser *parser,
break;
case s_res_first_http_major:
- if (ch < '1' || ch > '9') goto error;
+ if (ch < '1' || ch > '9') {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
parser->http_major = ch - '0';
state = s_res_http_major;
break;
@@ -488,18 +531,29 @@ size_t http_parser_execute (http_parser *parser,
break;
}
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
parser->http_major *= 10;
parser->http_major += ch - '0';
- if (parser->http_major > 999) goto error;
+ if (parser->http_major > 999) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
break;
}
/* first digit of minor HTTP version */
case s_res_first_http_minor:
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
parser->http_minor = ch - '0';
state = s_res_http_minor;
break;
@@ -512,12 +566,19 @@ size_t http_parser_execute (http_parser *parser,
break;
}
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
parser->http_minor *= 10;
parser->http_minor += ch - '0';
- if (parser->http_minor > 999) goto error;
+ if (parser->http_minor > 999) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
break;
}
@@ -527,6 +588,8 @@ size_t http_parser_execute (http_parser *parser,
if (ch == ' ') {
break;
}
+
+ SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
parser->status_code = ch - '0';
@@ -548,6 +611,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_header_field_start;
break;
default:
+ SET_ERRNO(HPE_INVALID_STATUS);
goto error;
}
break;
@@ -556,7 +620,11 @@ size_t http_parser_execute (http_parser *parser,
parser->status_code *= 10;
parser->status_code += ch - '0';
- if (parser->status_code > 999) goto error;
+ if (parser->status_code > 999) {
+ SET_ERRNO(HPE_INVALID_STATUS);
+ goto error;
+ }
+
break;
}
@@ -588,7 +656,10 @@ size_t http_parser_execute (http_parser *parser,
CALLBACK2(message_begin);
- if (!IS_ALPHA(LOWER(ch))) goto error;
+ if (!IS_ALPHA(ch)) {
+ SET_ERRNO(HPE_INVALID_METHOD);
+ goto error;
+ }
start_req_method_assign:
parser->method = (enum http_method) 0;
@@ -609,7 +680,9 @@ size_t http_parser_execute (http_parser *parser,
case 'S': parser->method = HTTP_SUBSCRIBE; break;
case 'T': parser->method = HTTP_TRACE; break;
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
- default: goto error;
+ default:
+ SET_ERRNO(HPE_INVALID_METHOD);
+ goto error;
}
state = s_req_method;
break;
@@ -617,8 +690,10 @@ size_t http_parser_execute (http_parser *parser,
case s_req_method:
{
- if (ch == '\0')
+ if (ch == '\0') {
+ SET_ERRNO(HPE_INVALID_METHOD);
goto error;
+ }
const char *matcher = method_strings[parser->method];
if (ch == ' ' && matcher[index] == '\0') {
@@ -630,6 +705,8 @@ size_t http_parser_execute (http_parser *parser,
parser->method = HTTP_CHECKOUT;
} else if (index == 2 && ch == 'P') {
parser->method = HTTP_COPY;
+ } else {
+ goto error;
}
} else if (parser->method == HTTP_MKCOL) {
if (index == 1 && ch == 'O') {
@@ -640,18 +717,25 @@ size_t http_parser_execute (http_parser *parser,
parser->method = HTTP_MSEARCH;
} else if (index == 2 && ch == 'A') {
parser->method = HTTP_MKACTIVITY;
+ } else {
+ goto error;
+ }
+ } else if (index == 1 && parser->method == HTTP_POST) {
+ if (ch == 'R') {
+ parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
+ } else if (ch == 'U') {
+ parser->method = HTTP_PUT;
+ } else if (ch == 'A') {
+ parser->method = HTTP_PATCH;
+ } else {
+ goto error;
}
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') {
- parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
- parser->method = HTTP_PUT;
- } else if (index == 1 && parser->method == HTTP_POST && ch == 'A') {
- parser->method = HTTP_PATCH;
} else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
parser->method = HTTP_UNSUBSCRIBE;
} else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
parser->method = HTTP_PROPPATCH;
} else {
+ SET_ERRNO(HPE_INVALID_METHOD);
goto error;
}
@@ -664,13 +748,10 @@ size_t http_parser_execute (http_parser *parser,
if (ch == '/' || ch == '*') {
MARK(url);
- MARK(path);
state = s_req_path;
break;
}
- c = LOWER(ch);
-
/* Proxied requests are followed by scheme of an absolute URI (alpha).
* CONNECT is followed by a hostname, which begins with alphanum.
* All other methods are followed by '/' or '*' (handled above).
@@ -681,20 +762,20 @@ size_t http_parser_execute (http_parser *parser,
break;
}
+ SET_ERRNO(HPE_INVALID_URL);
goto error;
}
case s_req_schema:
{
- c = LOWER(ch);
-
- if (IS_ALPHA(c)) break;
+ if (IS_ALPHA(ch)) break;
if (ch == ':') {
state = s_req_schema_slash;
break;
}
+ SET_ERRNO(HPE_INVALID_URL);
goto error;
}
@@ -710,14 +791,12 @@ size_t http_parser_execute (http_parser *parser,
case s_req_host:
{
- c = LOWER(ch);
if (IS_HOST_CHAR(ch)) break;
switch (ch) {
case ':':
state = s_req_port;
break;
case '/':
- MARK(path);
state = s_req_path;
break;
case ' ':
@@ -732,6 +811,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_req_query_string_start;
break;
default:
+ SET_ERRNO(HPE_INVALID_HOST);
goto error;
}
break;
@@ -742,7 +822,6 @@ size_t http_parser_execute (http_parser *parser,
if (IS_NUM(ch)) break;
switch (ch) {
case '/':
- MARK(path);
state = s_req_path;
break;
case ' ':
@@ -757,6 +836,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_req_query_string_start;
break;
default:
+ SET_ERRNO(HPE_INVALID_PORT);
goto error;
}
break;
@@ -769,32 +849,28 @@ size_t http_parser_execute (http_parser *parser,
switch (ch) {
case ' ':
CALLBACK(url);
- CALLBACK(path);
state = s_req_http_start;
break;
case CR:
CALLBACK(url);
- CALLBACK(path);
parser->http_major = 0;
parser->http_minor = 9;
state = s_req_line_almost_done;
break;
case LF:
CALLBACK(url);
- CALLBACK(path);
parser->http_major = 0;
parser->http_minor = 9;
state = s_header_field_start;
break;
case '?':
- CALLBACK(path);
state = s_req_query_string_start;
break;
case '#':
- CALLBACK(path);
state = s_req_fragment_start;
break;
default:
+ SET_ERRNO(HPE_INVALID_PATH);
goto error;
}
break;
@@ -803,7 +879,6 @@ size_t http_parser_execute (http_parser *parser,
case s_req_query_string_start:
{
if (IS_URL_CHAR(ch)) {
- MARK(query_string);
state = s_req_query_string;
break;
}
@@ -831,6 +906,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_req_fragment_start;
break;
default:
+ SET_ERRNO(HPE_INVALID_QUERY_STRING);
goto error;
}
break;
@@ -846,28 +922,25 @@ size_t http_parser_execute (http_parser *parser,
break;
case ' ':
CALLBACK(url);
- CALLBACK(query_string);
state = s_req_http_start;
break;
case CR:
CALLBACK(url);
- CALLBACK(query_string);
parser->http_major = 0;
parser->http_minor = 9;
state = s_req_line_almost_done;
break;
case LF:
CALLBACK(url);
- CALLBACK(query_string);
parser->http_major = 0;
parser->http_minor = 9;
state = s_header_field_start;
break;
case '#':
- CALLBACK(query_string);
state = s_req_fragment_start;
break;
default:
+ SET_ERRNO(HPE_INVALID_QUERY_STRING);
goto error;
}
break;
@@ -876,7 +949,6 @@ size_t http_parser_execute (http_parser *parser,
case s_req_fragment_start:
{
if (IS_URL_CHAR(ch)) {
- MARK(fragment);
state = s_req_fragment;
break;
}
@@ -899,12 +971,12 @@ size_t http_parser_execute (http_parser *parser,
state = s_header_field_start;
break;
case '?':
- MARK(fragment);
state = s_req_fragment;
break;
case '#':
break;
default:
+ SET_ERRNO(HPE_INVALID_FRAGMENT);
goto error;
}
break;
@@ -917,19 +989,16 @@ size_t http_parser_execute (http_parser *parser,
switch (ch) {
case ' ':
CALLBACK(url);
- CALLBACK(fragment);
state = s_req_http_start;
break;
case CR:
CALLBACK(url);
- CALLBACK(fragment);
parser->http_major = 0;
parser->http_minor = 9;
state = s_req_line_almost_done;
break;
case LF:
CALLBACK(url);
- CALLBACK(fragment);
parser->http_major = 0;
parser->http_minor = 9;
state = s_header_field_start;
@@ -938,6 +1007,7 @@ size_t http_parser_execute (http_parser *parser,
case '#':
break;
default:
+ SET_ERRNO(HPE_INVALID_FRAGMENT);
goto error;
}
break;
@@ -951,6 +1021,7 @@ size_t http_parser_execute (http_parser *parser,
case ' ':
break;
default:
+ SET_ERRNO(HPE_INVALID_CONSTANT);
goto error;
}
break;
@@ -977,7 +1048,11 @@ size_t http_parser_execute (http_parser *parser,
/* first digit of major HTTP version */
case s_req_first_http_major:
- if (ch < '1' || ch > '9') goto error;
+ if (ch < '1' || ch > '9') {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
parser->http_major = ch - '0';
state = s_req_http_major;
break;
@@ -990,18 +1065,29 @@ size_t http_parser_execute (http_parser *parser,
break;
}
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
parser->http_major *= 10;
parser->http_major += ch - '0';
- if (parser->http_major > 999) goto error;
+ if (parser->http_major > 999) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
break;
}
/* first digit of minor HTTP version */
case s_req_first_http_minor:
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
parser->http_minor = ch - '0';
state = s_req_http_minor;
break;
@@ -1021,24 +1107,36 @@ size_t http_parser_execute (http_parser *parser,
/* XXX allow spaces after digit? */
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
parser->http_minor *= 10;
parser->http_minor += ch - '0';
- if (parser->http_minor > 999) goto error;
+ if (parser->http_minor > 999) {
+ SET_ERRNO(HPE_INVALID_VERSION);
+ goto error;
+ }
+
break;
}
/* end of request line */
case s_req_line_almost_done:
{
- if (ch != LF) goto error;
+ if (ch != LF) {
+ SET_ERRNO(HPE_LF_EXPECTED);
+ goto error;
+ }
+
state = s_header_field_start;
break;
}
case s_header_field_start:
+ header_field_start:
{
if (ch == CR) {
state = s_headers_almost_done;
@@ -1054,7 +1152,10 @@ size_t http_parser_execute (http_parser *parser,
c = TOKEN(ch);
- if (!c) goto error;
+ if (!c) {
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
+ goto error;
+ }
MARK(header_field);
@@ -1211,20 +1312,19 @@ size_t http_parser_execute (http_parser *parser,
break;
}
+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
goto error;
}
case s_header_value_start:
{
- if (ch == ' ') break;
+ if (ch == ' ' || ch == '\t') break;
MARK(header_value);
state = s_header_value;
index = 0;
- c = LOWER(ch);
-
if (ch == CR) {
CALLBACK(header_value);
header_state = h_general;
@@ -1238,6 +1338,8 @@ size_t http_parser_execute (http_parser *parser,
break;
}
+ c = LOWER(ch);
+
switch (header_state) {
case h_upgrade:
parser->flags |= F_UPGRADE;
@@ -1254,7 +1356,11 @@ size_t http_parser_execute (http_parser *parser,
break;
case h_content_length:
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ goto error;
+ }
+
parser->content_length = ch - '0';
break;
@@ -1279,7 +1385,6 @@ size_t http_parser_execute (http_parser *parser,
case s_header_value:
{
- c = LOWER(ch);
if (ch == CR) {
CALLBACK(header_value);
@@ -1292,6 +1397,8 @@ size_t http_parser_execute (http_parser *parser,
goto header_almost_done;
}
+ c = LOWER(ch);
+
switch (header_state) {
case h_general:
break;
@@ -1303,7 +1410,11 @@ size_t http_parser_execute (http_parser *parser,
case h_content_length:
if (ch == ' ') break;
- if (!IS_NUM(ch)) goto error;
+ if (!IS_NUM(ch)) {
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+ goto error;
+ }
+
parser->content_length *= 10;
parser->content_length += ch - '0';
break;
@@ -1359,7 +1470,7 @@ size_t http_parser_execute (http_parser *parser,
{
STRICT_CHECK(ch != LF);
- state = s_header_field_start;
+ state = s_header_value_lws;
switch (header_state) {
case h_connection_keep_alive:
@@ -1377,6 +1488,18 @@ size_t http_parser_execute (http_parser *parser,
break;
}
+ case s_header_value_lws:
+ {
+ if (ch == ' ' || ch == '\t')
+ state = s_header_value_start;
+ else
+ {
+ state = s_header_field_start;
+ goto header_field_start;
+ }
+ break;
+ }
+
case s_headers_almost_done:
headers_almost_done:
{
@@ -1412,6 +1535,7 @@ size_t http_parser_execute (http_parser *parser,
default:
parser->state = state;
+ SET_ERRNO(HPE_CB_headers_complete);
return p - data; /* Error */
}
}
@@ -1419,7 +1543,7 @@ size_t http_parser_execute (http_parser *parser,
/* Exit, the rest of the connect is in a different protocol. */
if (parser->upgrade) {
CALLBACK2(message_complete);
- return (p - data);
+ return (p - data) + 1;
}
if (parser->flags & F_SKIPBODY) {
@@ -1478,9 +1602,13 @@ size_t http_parser_execute (http_parser *parser,
assert(nread == 1);
assert(parser->flags & F_CHUNKED);
- c = unhex[(unsigned char)ch];
- if (c == -1) goto error;
- parser->content_length = c;
+ unhex_val = unhex[(unsigned char)ch];
+ if (unhex_val == -1) {
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
+ goto error;
+ }
+
+ parser->content_length = unhex_val;
state = s_chunk_size;
break;
}
@@ -1494,18 +1622,20 @@ size_t http_parser_execute (http_parser *parser,
break;
}
- c = unhex[(unsigned char)ch];
+ unhex_val = unhex[(unsigned char)ch];
- if (c == -1) {
+ if (unhex_val == -1) {
if (ch == ';' || ch == ' ') {
state = s_chunk_parameters;
break;
}
+
+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
goto error;
}
parser->content_length *= 16;
- parser->content_length += c;
+ parser->content_length += unhex_val;
break;
}
@@ -1569,16 +1699,14 @@ size_t http_parser_execute (http_parser *parser,
default:
assert(0 && "unhandled state");
+ SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
goto error;
}
}
- CALLBACK_NOCLEAR(header_field);
- CALLBACK_NOCLEAR(header_value);
- CALLBACK_NOCLEAR(fragment);
- CALLBACK_NOCLEAR(query_string);
- CALLBACK_NOCLEAR(path);
- CALLBACK_NOCLEAR(url);
+ CALLBACK(header_field);
+ CALLBACK(header_value);
+ CALLBACK(url);
parser->state = state;
parser->header_state = header_state;
@@ -1588,7 +1716,10 @@ size_t http_parser_execute (http_parser *parser,
return len;
error:
- parser->state = s_dead;
+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
+ SET_ERRNO(HPE_UNKNOWN);
+ }
+
return (p - data);
}
@@ -1629,4 +1760,17 @@ http_parser_init (http_parser *parser, enum http_parser_type t)
parser->upgrade = 0;
parser->flags = 0;
parser->method = 0;
+ parser->http_errno = 0;
+}
+
+const char *
+http_errno_name(enum http_errno err) {
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
+ return http_strerror_tab[err].name;
+}
+
+const char *
+http_errno_description(enum http_errno err) {
+ assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
+ return http_strerror_tab[err].description;
}