X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=php_http_message_parser.c;h=fae3df3f46fc9021e5549bfd5ebfa8890984e2dd;hb=287edcbfb698ff402588f7057dae0bc994d6e8e4;hp=fce24ed2cffc4e49eae22f457f66c5dad3303f9f;hpb=a07b79b1871054ca17e48b69445b4dc201f24662;p=m6w6%2Fext-http diff --git a/php_http_message_parser.c b/php_http_message_parser.c index fce24ed..fae3df3 100644 --- a/php_http_message_parser.c +++ b/php_http_message_parser.c @@ -1,4 +1,16 @@ -#include "php_http.h" +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2011, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" typedef struct php_http_message_parser_state_spec { php_http_message_parser_state_t state; @@ -34,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)); @@ -90,18 +102,83 @@ 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_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 + buf.used - 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 @@ -130,7 +207,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; @@ -222,10 +299,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; } } @@ -251,7 +334,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; } } @@ -316,7 +399,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; } @@ -401,3 +484,13 @@ PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_h return php_http_message_parser_state_is(parser); } + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ +