X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_message_api.c;h=76e1d22dbe6a3ba17e3d4ab2467ba9b9eb51f247;hp=a4490d8c4535b5a16d31535ebbd45b71bc7a05ed;hb=e434da0fad7db62d86c236c68b22150165f2647a;hpb=46ef6bdcdea32310a17dc95eadb14936125dcb51 diff --git a/http_message_api.c b/http_message_api.c index a4490d8..76e1d22 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -23,10 +23,30 @@ #include "php_http.h" #include "php_http_std_defs.h" #include "php_http_message_api.h" +#include "php_http_api.h" #include "php_http_headers_api.h" #include "phpstr/phpstr.h" +#define http_message_parse_nested(msg, begin, length) _http_message_parse_nested((msg), (begin), (length) TSRMLS_CC) +static inline http_message *_http_message_parse_nested(http_message *msg, const char *begin, size_t length TSRMLS_DC) +{ + http_message *new; + + while (isspace(*begin)) { + ++begin; + if (!length--) { + return NULL; + } + } + + if (new = http_message_parse(begin, length)) { + new->nested = msg; + return new; + } + return NULL; +} + PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_message_type type) { if (!message) { @@ -41,11 +61,11 @@ PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_mes return message; } -PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t message_length, zend_bool dup TSRMLS_DC) +PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t message_length TSRMLS_DC) { char *body = NULL; size_t header_length = 0; - http_message *msg; + zend_bool free_msg = msg ? 0 : 1; if (message_length < HTTP_MSG_MIN_SIZE) { return NULL; @@ -55,9 +75,7 @@ PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t message_ return NULL; } - msg = http_message_new(); - msg->len = message_length; - msg->raw = dup ? estrndup(message, message_length) : message; + msg = http_message_init(msg); if (body = strstr(message, HTTP_CRLF HTTP_CRLF)) { body += lenof(HTTP_CRLF HTTP_CRLF); @@ -65,16 +83,43 @@ PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t message_ } else { header_length = message_length; } - - if (SUCCESS != http_parse_headers_cb(message, header_length, &msg->hdrs, 1, http_message_parse_headers_callback, (void **) &msg)) { - http_message_free(msg); + + if (SUCCESS != http_parse_headers_cb((char *)message, header_length, &msg->hdrs, 1, http_message_parse_headers_callback, (void **) &msg)) { + if (free_msg) { + http_message_free(msg); + } return NULL; } - + if (body) { - phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length); + zval **c; + http_message *nested; + + if (SUCCESS == zend_hash_find(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void **) &c)) { + long len = atol(Z_STRVAL_PP(c)); + phpstr_from_string_ex(PHPSTR(msg), body, len); + if (nested = http_message_parse_nested(msg, body + len, message + message_length - body - len)) { + return nested; + } + } else if ( + SUCCESS == zend_hash_find(&msg->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding"), (void **) &c) && + !strcasecmp("chunked", Z_STRVAL_PP(c))) { + + char *decoded, *end; + size_t decoded_len; + + if (end = http_chunked_decode(body, message_length - header_length, &decoded, &decoded_len)) { + phpstr_from_string_ex(PHPSTR(msg), decoded, decoded_len); + efree(decoded); + if (nested = http_message_parse_nested(msg, end, message + message_length - end)) { + return nested; + } + } + } else { + phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length); + } } - + return msg; } @@ -82,22 +127,22 @@ PHP_HTTP_API void _http_message_parse_headers_callback(void **message, char *htt { http_message *old = (http_message *) *message; http_message *new; - + if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) { new = http_message_new(); - + new->nested = old; *message = new; *headers = &new->hdrs; } else { new = old; } - + // response if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) { new->type = HTTP_MSG_RESPONSE; new->info.response.http_version = atof(http_line + lenof("HTTP/")); - new->info.response.status = atoi(http_line + lenof("HTTP/1.1 ")); + new->info.response.code = atoi(http_line + lenof("HTTP/1.1 ")); } else // request if (!strncmp(http_line + line_length - lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) { @@ -117,49 +162,52 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_ ulong idx; zval **header; - phpstr_init_ex(&str, msg->len, 1); - /* set sane alloc size */ - str.size = 4096; - - switch (msg->type) - { - case HTTP_MSG_REQUEST: - phpstr_appendf(&str, "%s %s HTTP/%1.1f" HTTP_CRLF, - msg->info.request.method, - msg->info.request.URI, - msg->info.request.http_version); - break; - - case HTTP_MSG_RESPONSE: - phpstr_appendf(&str, "HTTP/%1.1f %d" HTTP_CRLF, - msg->info.response.http_version, - msg->info.response.status); - break; - } + phpstr_init_ex(&str, 4096, 0); + + do { + + switch (msg->type) + { + case HTTP_MSG_REQUEST: + phpstr_appendf(&str, "%s %s HTTP/%1.1f" HTTP_CRLF, + msg->info.request.method, + msg->info.request.URI, + msg->info.request.http_version); + break; - FOREACH_HASH_KEYVAL(&msg->hdrs, key, idx, header) { - if (key) { - zval **single_header; - - switch (Z_TYPE_PP(header)) - { - case IS_STRING: - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(header)); - break; - - case IS_ARRAY: - FOREACH_VAL(*header, single_header) { - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(single_header)); - } - break; + case HTTP_MSG_RESPONSE: + phpstr_appendf(&str, "HTTP/%1.1f %d" HTTP_CRLF, + msg->info.response.http_version, + msg->info.response.code); + break; + } + + FOREACH_HASH_KEYVAL(&msg->hdrs, key, idx, header) { + if (key) { + zval **single_header; + + switch (Z_TYPE_PP(header)) + { + case IS_STRING: + phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(header)); + break; + + case IS_ARRAY: + FOREACH_VAL(*header, single_header) { + phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(single_header)); + } + break; + } + + key = NULL; } - - key = NULL; } - } - phpstr_appends(&str, HTTP_CRLF); - phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg)); + phpstr_appends(&str, HTTP_CRLF); + phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg)); + phpstr_appends(&str, HTTP_CRLF); + + } while (msg = msg->nested); data = phpstr_data(&str, string, length); if (!string) { @@ -174,15 +222,14 @@ PHP_HTTP_API void _http_message_dtor(http_message *message) if (message) { zend_hash_destroy(&message->hdrs); phpstr_dtor(PHPSTR(message)); - if (message->raw) { - efree(message->raw); - } if (message->type == HTTP_MSG_REQUEST) { if (message->info.request.method) { efree(message->info.request.method); + message->info.request.method = NULL; } if (message->info.request.URI) { efree(message->info.request.URI); + message->info.request.URI = NULL; } } } @@ -193,6 +240,7 @@ PHP_HTTP_API void _http_message_free(http_message *message) if (message) { if (message->nested) { http_message_free(message->nested); + message->nested = NULL; } http_message_dtor(message); efree(message);