X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=php_http_message_parser.c;h=3e46674cf3dfa728a62b95a2d93f99fcbd4eb315;hp=ca2027b5724eccff9ebac7318f56de787ba1fd5f;hb=25f0c16244fc5f8b2c9d9bfddab8a541d2521789;hpb=9de008496a220c769a745cd1eead0a3b3d7d6cca diff --git a/php_http_message_parser.c b/php_http_message_parser.c index ca2027b..3e46674 100644 --- a/php_http_message_parser.c +++ b/php_http_message_parser.c @@ -12,6 +12,10 @@ #include "php_http_api.h" +#ifndef DBG_PARSER +# define DBG_PARSER 0 +#endif + typedef struct php_http_message_parser_state_spec { php_http_message_parser_state_t state; unsigned need_data:1; @@ -29,6 +33,17 @@ static const php_http_message_parser_state_spec_t php_http_message_parser_states {PHP_HTTP_MESSAGE_PARSER_STATE_DONE, 0} }; +#if DBG_PARSER +const char *php_http_message_parser_state_name(php_http_message_parser_state_t state) { + const char *states[] = {"START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "DONE"}; + + if (state < 0 || state > (sizeof(states)/sizeof(char*))-1) { + return "FAILURE"; + } + return states[state]; +} +#endif + PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser TSRMLS_DC) { if (!parser) { @@ -46,11 +61,11 @@ PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_me PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...) { + php_http_message_parser_state_t state; va_list va_args; unsigned i; - va_start(va_args, argc); - php_http_message_parser_state_t state; + va_start(va_args, argc); for (i = 0; i < argc; ++i) { state = va_arg(va_args, php_http_message_parser_state_t); zend_stack_push(&parser->stack, &state, sizeof(state)); @@ -102,17 +117,20 @@ PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parse } } -PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_stream *s, php_http_message_t **message) +PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_stream *s, unsigned flags, php_http_message_t **message) { php_http_buffer_t buf; + php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_START; TSRMLS_FETCH_FROM_CTX(parser->ts); php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC); while (!php_stream_eof(s)) { size_t len = 0; - - switch (php_http_message_parser_state_is(parser)) { +#if DBG_PARSER + fprintf(stderr, "#SP: %s (f:%u)\n", php_http_message_parser_state_name(state), flags); +#endif + switch (state) { case PHP_HTTP_MESSAGE_PARSER_STATE_START: case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER: case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE: @@ -140,10 +158,11 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_strea len -= read; } else { + php_http_buffer_resize(&buf, 24); php_stream_get_line(s, buf.data, buf.free, &len); php_http_buffer_account(&buf, len); - len = strtoul(buf.data - len, NULL, 16); + len = strtoul(buf.data + buf.used - len, NULL, 16); } break; @@ -159,7 +178,7 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_strea return php_http_message_parser_state_is(parser); } - php_http_message_parser_parse(parser, &buf, 0, message); + state = php_http_message_parser_parse(parser, &buf, flags, message); } php_http_buffer_dtor(&buf); @@ -169,15 +188,19 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_strea PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message) { - TSRMLS_FETCH_FROM_CTX(parser->ts); char *str = NULL; size_t len = 0; size_t cut = 0; + TSRMLS_FETCH_FROM_CTX(parser->ts); while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is(parser)].need_data) { -#if 0 - const char *state[] = {"START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "DONE"}; - fprintf(stderr, "#MP: %s (%d)\n", php_http_message_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_message_parser_state_is(parser)], message && *message ? (*message)->type : -1); +#if DBG_PARSER + fprintf(stderr, "#MP: %s (f: %u, t:%d, l:%zu)\n", + php_http_message_parser_state_name(php_http_message_parser_state_is(parser)), + flags, + message && *message ? (*message)->type : -1, + buffer->used + ); _dpf(0, buffer->data, buffer->used); #endif @@ -298,10 +321,16 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h if (h_cl) { char *stop; - parser->body_length = strtoul(Z_STRVAL_PP(h_cl), &stop, 10); + if (Z_TYPE_PP(h_cl) == IS_STRING) { + parser->body_length = strtoul(Z_STRVAL_PP(h_cl), &stop, 10); - if (stop != Z_STRVAL_PP(h_cl)) { - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + if (stop != Z_STRVAL_PP(h_cl)) { + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + break; + } + } else if (Z_TYPE_PP(h_cl) == IS_LONG) { + parser->body_length = Z_LVAL_PP(h_cl); + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); break; } } @@ -327,7 +356,7 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h if (end >= start && (!total || end < total)) { parser->body_length = end + 1 - start; - php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); + php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH); break; } } @@ -429,7 +458,7 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h len = dec_len; if (php_http_encoding_stream_done(parser->dechunk)) { - cut = buffer->used - PHP_HTTP_BUFFER_LEN(parser->dechunk->ctx); + cut = buffer->used - PHP_HTTP_BUFFER(parser->dechunk->ctx)->used; php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); } else { cut = buffer->used; @@ -470,6 +499,10 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h } php_http_buffer_cut(buffer, 0, ptr - buffer->data); + + if (!(flags & PHP_HTTP_MESSAGE_PARSER_GREEDY)) { + return PHP_HTTP_MESSAGE_PARSER_STATE_DONE; + } break; } }