X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=php_http_message_parser.c;h=ecdfe37b51cdb3bba4e1c6c962c8a3649543cc39;hp=3eb85719f2e8fe5523852976fef814cc5e8c0cf2;hb=305ac2f007710b684d96b05f33964b4f6a4e3e4d;hpb=8d05291f42b3b42159b3fe91492aa4862f3d4405 diff --git a/php_http_message_parser.c b/php_http_message_parser.c index 3eb8571..ecdfe37 100644 --- a/php_http_message_parser.c +++ b/php_http_message_parser.c @@ -10,7 +10,7 @@ +--------------------------------------------------------------------+ */ -#include "php_http.h" +#include "php_http_api.h" typedef struct php_http_message_parser_state_spec { php_http_message_parser_state_t state; @@ -46,11 +46,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,18 +102,82 @@ 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_buffer_t buf; + 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)) { + case PHP_HTTP_MESSAGE_PARSER_STATE_START: + case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER: + case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE: + /* read line */ + php_stream_get_line(s, buf.data + buf.used, buf.free, &len); + php_http_buffer_account(&buf, len); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB: + /* read all */ + php_http_buffer_account(&buf, php_stream_read(s, buf.data + buf.used, buf.free)); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH: + /* read body_length */ + php_http_buffer_account(&buf, php_stream_read(s, buf.data + buf.used, MIN(buf.free, parser->body_length))); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED: + /* duh, this is very naive */ + if (len) { + size_t read = php_stream_read(s, buf.data + buf.used, MIN(len, buf.free)); + + php_http_buffer_account(&buf, read); + + len -= read; + } else { + php_stream_get_line(s, buf.data, buf.free, &len); + php_http_buffer_account(&buf, len); + + len = strtoul(buf.data - len, NULL, 16); + } + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY: + case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE: + /* should not occur */ + abort(); + break; + + case PHP_HTTP_MESSAGE_PARSER_STATE_DONE: + case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE: + php_http_buffer_dtor(&buf); + return php_http_message_parser_state_is(parser); + } + + php_http_message_parser_parse(parser, &buf, 0, message); + } + + php_http_buffer_dtor(&buf); + return PHP_HTTP_MESSAGE_PARSER_STATE_DONE; +} + 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)->type); + 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); _dpf(0, buffer->data, buffer->used); #endif @@ -142,7 +206,7 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h { unsigned header_parser_flags = (flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP) ? PHP_HTTP_HEADER_PARSER_CLEANUP : 0; - switch (php_http_header_parser_parse(&parser->header, buffer, header_parser_flags, &(*message)->hdrs, (php_http_info_callback_t) php_http_message_info_callback, message)) { + switch (php_http_header_parser_parse(&parser->header, buffer, header_parser_flags, *message ? &(*message)->hdrs : NULL, (php_http_info_callback_t) php_http_message_info_callback, message)) { case PHP_HTTP_HEADER_PARSER_STATE_FAILURE: return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE; @@ -328,7 +392,7 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h len = buffer->used; cut = len; - php_http_message_parser_state_push(parser, 2, !buffer->used?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); + php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY); break; }