X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_message_api.c;h=1e6ac3a2a8e6479ffcb2398867df0a4016ee661e;hp=b89e0a89a5ec0d4c72ae7036710069defbc9d8ea;hb=80fd11fc5b72c8fadea499aec6e617d415334c2d;hpb=0ac32c9b8590e88a5f110cc8b3154001d5c0c089 diff --git a/http_message_api.c b/http_message_api.c index b89e0a8..1e6ac3a 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -27,36 +27,6 @@ #include "phpstr/phpstr.h" -PHP_HTTP_API void _http_message_dtor(http_message *message) -{ - if (message) { - zend_hash_destroy(&message->hdrs); - phpstr_dtor(PHPSTR(message)); - if (message->dup && message->raw.dup) { - efree(message->raw.dup); - } - if (message->type == HTTP_MSG_REQUEST) { - if (message->info.request.method) { - efree(message->info.request.method); - } - if (message->info.request.URI) { - efree(message->info.request.URI); - } - } - } -} - -PHP_HTTP_API void _http_message_free(http_message *message) -{ - if (message) { - if (message->nested) { - http_message_free(message->nested); - } - http_message_dtor(message); - efree(message); - } -} - PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_message_type type) { if (!message) { @@ -71,68 +41,75 @@ 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(const char *message, size_t length, zend_bool dup TSRMLS_DC) +PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, char *message, size_t message_length, zend_bool dup TSRMLS_DC) { - const char *message_start = message, *body = NULL; - size_t message_length = length, header_length = 0; - http_message *msg; + char *body = NULL; + size_t header_length = 0; + zend_bool free_msg = msg ? 0 : 1; - if (length < HTTP_MSG_MIN_SIZE) { + if (message_length < HTTP_MSG_MIN_SIZE) { return NULL; } + if (!message) { return NULL; } - if (!(message_start = strstr(message, HTTP_CRLF))) { + msg = http_message_init(msg); + msg->len = message_length; + msg->raw = dup ? estrndup(message, message_length) : message; + + if (body = strstr(message, HTTP_CRLF HTTP_CRLF)) { + body += lenof(HTTP_CRLF HTTP_CRLF); + header_length = body - 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)) { + if (free_msg) { + http_message_free(msg); + } return NULL; } - msg = http_message_init(); + if (body) { + phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length); + } - // response - if (!strncmp(message, "HTTP/1.", lenof("HTTP/1."))) { - msg->type = HTTP_MSG_RESPONSE; - msg->info.response.http_version = atof(message + lenof("HTTP/")); - msg->info.response.status = atoi(message + lenof("HTTP/1.1 ")); - } else - // request - if (!strncmp(message_start - lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) { - const char *method_sep_uri = strchr(message, ' '); + return msg; +} - msg->type = HTTP_MSG_REQUEST; - msg->info.request.http_version = atof(message_start - lenof("1.1")); - msg->info.request.method = estrndup(message, method_sep_uri - message); - msg->info.request.URI = estrndup(method_sep_uri + 1, message_start - method_sep_uri - 1 - lenof(" HTTP/1.1")); - } else { - http_message_free(msg); - return NULL; - } +PHP_HTTP_API void _http_message_parse_headers_callback(void **message, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC) +{ + http_message *old = (http_message *) *message; + http_message *new; - message_start += lenof(HTTP_CRLF); - message_length -= message_start - message; + if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) { + new = http_message_new(); - if (msg->dup = dup) { - msg->len = length; - msg->raw.dup = estrndup(message, length); + new->nested = old; + *message = new; + *headers = &new->hdrs; } else { - msg->len = length; - msg->raw.ptr = message; + new = old; } - if (body = strstr(message_start, HTTP_CRLF HTTP_CRLF)) { - body += lenof(HTTP_CRLF HTTP_CRLF); - header_length = body - message_start; - phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length); - } else { - header_length = message_length; - } + // 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 ")); + } else + // request + if (!strncmp(http_line + line_length - lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) { + const char *method_sep_uri = strchr(http_line, ' '); - if (SUCCESS != http_parse_headers_ex(message_start, header_length, &msg->hdrs, 1)) { - http_message_free(msg); - return NULL; + new->type = HTTP_MSG_REQUEST; + new->info.request.http_version = atof(http_line + line_length - lenof("1.1")); + new->info.request.method = estrndup(http_line, method_sep_uri - http_line); + new->info.request.URI = estrndup(method_sep_uri + 1, http_line + line_length - method_sep_uri - 1 - lenof(" HTTP/1.1")); } - return msg; } PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length) @@ -143,6 +120,8 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_ zval **header; phpstr_init_ex(&str, msg->len, 1); + /* set sane alloc size */ + str.size = 4096; switch (msg->type) { @@ -162,14 +141,27 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_ FOREACH_HASH_KEYVAL(&msg->hdrs, key, idx, header) { if (key) { - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(header)); + 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; } } phpstr_appends(&str, HTTP_CRLF); - phpstr_append(&str, msg->body.data, msg->body.used); - phpstr_fix(&str); + phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg)); data = phpstr_data(&str, string, length); if (!string) { @@ -178,3 +170,46 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_ phpstr_dtor(&str); } + +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); + message->raw = NULL; + } + 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; + } + } + } +} + +PHP_HTTP_API void _http_message_free(http_message *message) +{ + if (message) { + if (message->nested) { + http_message_free(message->nested); + } + http_message_dtor(message); + efree(message); + } +} + +/* + * 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 + */ +