From c2b4f0332ead5425b183d2487ab5f25663f1009f Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 2 May 2005 20:58:00 +0000 Subject: [PATCH] flush --- CREDITS | 1 + http.c | 2 +- http_api.c | 31 ++- http_curl_api.c | 6 +- http_functions.c | 13 +- http_headers_api.c | 47 +++-- http_message_api.c | 409 +++++++++++++++++++++++++++----------- http_message_object.c | 80 ++++---- http_methods.c | 92 ++++++--- php_http_api.h | 2 +- php_http_headers_api.h | 13 +- php_http_message_api.h | 30 ++- php_http_message_object.h | 20 +- php_http_std_defs.h | 18 ++ 14 files changed, 514 insertions(+), 250 deletions(-) diff --git a/CREDITS b/CREDITS index a02e710..1b486cb 100644 --- a/CREDITS +++ b/CREDITS @@ -1,2 +1,3 @@ HTTP Michael Wallner, Sara Golemon, Daniel Stenberg (libcurl) + diff --git a/http.c b/http.c index f574045..b26751a 100644 --- a/http.c +++ b/http.c @@ -194,7 +194,7 @@ static inline void _http_globals_dtor(TSRMLS_D) static inline void _http_check_allowed_methods(char *methods, int length TSRMLS_DC) { if (length && SG(request_info).request_method) { - if (SUCCESS != http_check_method(SG(request_info).request_method, methods)) { + if (SUCCESS != http_check_method_ex(SG(request_info).request_method, methods)) { char *header = emalloc(length + sizeof("Allow: ")); sprintf(header, "Allow: %s", methods); http_exit(405, header); diff --git a/http_api.c b/http_api.c index e76846c..da469a9 100644 --- a/http_api.c +++ b/http_api.c @@ -132,7 +132,7 @@ PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_size, zen /* {{{ char *http_chunked_decode(char *, size_t, char **, size_t *) */ -PHP_HTTP_API char *_http_chunked_decode(const char *encoded, size_t encoded_len, +PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC) { const char *e_ptr; @@ -158,20 +158,6 @@ PHP_HTTP_API char *_http_chunked_decode(const char *encoded, size_t encoded_len, hex_len[i++] = *e_ptr++; } - /* reached the end */ - if (!strcmp(hex_len, "0")) { - break; - } - - /* new line */ - if (strncmp(e_ptr, HTTP_CRLF, 2)) { - http_error_ex(E_WARNING, HTTP_E_PARSE, - "Invalid character (expected 0x0D 0x0A; got: 0x%x(%c) 0x%x(%c))", - *e_ptr, *e_ptr, *(e_ptr + 1), *(e_ptr + 1)); - efree(*decoded); - return NULL; - } - /* hex to long */ { char *error = NULL; @@ -183,6 +169,19 @@ PHP_HTTP_API char *_http_chunked_decode(const char *encoded, size_t encoded_len, } } + /* reached the end */ + if (!chunk_len) { + break; + } + + /* new line */ + if (strncmp(e_ptr, HTTP_CRLF, 2)) { + http_error_ex(E_WARNING, HTTP_E_PARSE, + "Invalid character (expected 0x0D 0x0A; got: 0x%x 0x%x)", *e_ptr, *(e_ptr + 1)); + efree(*decoded); + return NULL; + } + memcpy(d_ptr, e_ptr += 2, chunk_len); d_ptr += chunk_len; e_ptr += chunk_len + 2; @@ -225,7 +224,7 @@ PHP_HTTP_API STATUS _http_split_response_ex(char *response, size_t response_len, memcpy(*body, real_body, *body_len); } - return http_parse_headers_ex(header, real_body ? response_len - *body_len : response_len, headers, 1); + return http_parse_headers_ex(header, headers, 1); } /* }}} */ diff --git a/http_curl_api.c b/http_curl_api.c index 7938573..e2d5911 100644 --- a/http_curl_api.c +++ b/http_curl_api.c @@ -106,7 +106,7 @@ static inline char *_http_curl_copystr(const char *str TSRMLS_DC) /* {{{ static size_t http_curl_callback(char *, size_t, size_t, void *) */ static size_t http_curl_callback(char *buf, size_t len, size_t n, void *s) { - return phpstr_append(PHPSTR(s), buf, len *= n); + return s ? phpstr_append(PHPSTR(s), buf, len * n) : len * n; } /* }}} */ @@ -211,7 +211,7 @@ static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options, ph /* compress, empty string enables deflate and gzip */ if (zoption = http_curl_getopt(options, "compress", IS_BOOL)) { if (Z_LVAL_P(zoption)) { - HTTP_CURL_OPT(ENCODING, ""); + HTTP_CURL_OPT(ENCODING, http_curl_copystr("")); } } @@ -332,7 +332,7 @@ static void _http_curl_setopts(CURL *ch, const char *url, HashTable *options, ph #define HTTP_CURL_OPT_STRING_EX(keyname, optname) \ if (!strcasecmp(key, #keyname)) { \ convert_to_string_ex(param); \ - HTTP_CURL_OPT(optname, Z_STRVAL_PP(param)); \ + HTTP_CURL_OPT(optname, http_curl_copystr(Z_STRVAL_PP(param))); \ key = NULL; \ continue; \ } diff --git a/http_functions.c b/http_functions.c index 5854e30..9bf3399 100644 --- a/http_functions.c +++ b/http_functions.c @@ -549,7 +549,7 @@ PHP_FUNCTION(http_chunked_decode) RETURN_FALSE; } - if (SUCCESS == http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) { + if (NULL != http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) { RETURN_STRINGL(decoded, decoded_len, 0); } else { RETURN_FALSE; @@ -566,7 +566,7 @@ PHP_FUNCTION(http_chunked_decode) * array( - * 'Status' => '200 Ok', + * 'Response Status' => '200 Ok', * 'Content-Type' => 'text/plain', * 'Content-Language' => 'en-US' * ), @@ -605,7 +605,7 @@ PHP_FUNCTION(http_split_response) */ PHP_FUNCTION(http_parse_headers) { - char *header, *rnrn; + char *header; int header_len; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) { @@ -613,11 +613,7 @@ PHP_FUNCTION(http_parse_headers) } array_init(return_value); - - if (rnrn = strstr(header, HTTP_CRLF HTTP_CRLF)) { - header_len = rnrn - header + 2; - } - if (SUCCESS != http_parse_headers(header, header_len, return_value)) { + if (SUCCESS != http_parse_headers(header, return_value)) { http_error(E_WARNING, HTTP_E_PARSE, "Could not parse HTTP headers"); zval_dtor(return_value); RETURN_FALSE; @@ -984,6 +980,7 @@ PHP_FUNCTION(http_build_query) PHP_FUNCTION(http_test) { + RETURN_NULL(); } /* diff --git a/http_headers_api.c b/http_headers_api.c index 09673e9..fad18e4 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -238,16 +238,22 @@ PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_ } /* }}} */ -/* {{{ STATUS http_parse_headers(char *, size_t, HashTable *, zend_bool) */ -PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len, - HashTable *headers, zend_bool prettify, - http_parse_headers_callback_t func, void **callback_data TSRMLS_DC) +/* {{{ STATUS http_parse_headers(char *, HashTable *, zend_bool) */ +PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_parse_headers_callback_t func, void **callback_data TSRMLS_DC) { - char *colon = NULL, *line = NULL, *begin = header; + const char *colon = NULL, *line = NULL, *begin = header, *crlfcrlf = NULL; + size_t header_len; zval array; Z_ARRVAL(array) = headers; + if (crlfcrlf = strstr(header, HTTP_CRLF HTTP_CRLF)) { + header_len = crlfcrlf - header; + } else { + header_len = strlen(header); + } + + if (header_len < 2 || !strchr(header, ':')) { http_error(E_WARNING, HTTP_E_PARSE, "Cannot parse too short or malformed HTTP headers"); return FAILURE; @@ -265,10 +271,10 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len, case '\n': if ((!(*line - 1)) || ((*line != ' ') && (*line != '\t'))) { /* response/request line */ - if ( (!strncmp(header, "HTTP/1.", lenof("HTTP/1."))) || - (!strncmp(line - lenof("HTTP/1.x\r") + value_len, "HTTP/1.", lenof("HTTP/1.")))) { + if ( (!strncmp(header, "HTTP/1.", lenof("HTTP/1."))) || + (!strncmp(line - lenof("HTTP/1.x" HTTP_CRLF) + value_len, "HTTP/1.", lenof("HTTP/1.")))) { if (func) { - func(callback_data, header, line - header + value_len, &headers TSRMLS_CC); + func(header, &headers, callback_data TSRMLS_CC); Z_ARRVAL(array) = headers; } } else @@ -324,6 +330,10 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len, efree(key); } } + /* stop at CRLF CRLF */ + if (!strncmp(HTTP_CRLF, line + 1, lenof(HTTP_CRLF))) { + return SUCCESS; + } colon = NULL; value_len = 0; header += line - header; @@ -341,21 +351,32 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len, } /* }}} */ -PHP_HTTP_API void _http_parse_headers_default_callback(void **cb_data, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC) +PHP_HTTP_API void _http_parse_headers_default_callback(const char *http_line, HashTable **headers, void **cb_data TSRMLS_DC) { zval array; + char *crlf = NULL; + size_t line_length; Z_ARRVAL(array) = *headers; + if (crlf = strstr(http_line, HTTP_CRLF)) { + line_length = crlf - http_line; + } else { + line_length = strlen(http_line); + } + /* response */ if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) { - add_assoc_stringl(&array, "Response Status", http_line + lenof("HTTP/1.x "), line_length - lenof("HTTP/1.x \r\n"), 1); + char *status = estrndup(http_line + lenof("HTTP/1.x "), line_length - lenof("HTTP/1.x ")); + add_assoc_stringl(&array, "Response Status", status, line_length - lenof("HTTP/1.x "), 0); } else /* request */ - if (!strncmp(http_line + line_length - lenof("HTTP/1.x\r\n"), "HTTP/1.", lenof("HTTP/1."))) { + if (!strncmp(http_line + line_length - lenof("HTTP/1.x"), "HTTP/1.", lenof("HTTP/1."))) { char *sep = strchr(http_line, ' '); + char *url = estrndup(sep + 1, strstr(sep, "HTTP/1.") - sep + 1 + 1); + char *met = estrndup(http_line, sep - http_line); - add_assoc_stringl(&array, "Request Method", http_line, sep - http_line, 1); - add_assoc_stringl(&array, "Request Uri", sep + 1, strstr(sep, "HTTP/1.") - sep + 1 + 1, 1); + add_assoc_stringl(&array, "Request Method", met, sep - http_line, 0); + add_assoc_stringl(&array, "Request Uri", url, strstr(sep, "HTTP/1.") - sep + 1 + 1, 0); } } diff --git a/http_message_api.c b/http_message_api.c index dd2cfff..1c977bf 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -22,27 +22,85 @@ #include "php.h" #include "php_http.h" #include "php_http_std_defs.h" -#include "php_http_message_api.h" #include "php_http_api.h" +#include "php_http_message_api.h" #include "php_http_headers_api.h" +#include "php_http_send_api.h" +#include "php_http_curl_api.h" +#include "php_http_url_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) +#define http_message_headers_cb _http_message_headers_cb +static void _http_message_headers_cb(const char *http_line, HashTable **headers, void **message TSRMLS_DC) { - http_message *new; + size_t line_length; + char *crlf = NULL; + http_message *new, *old = (http_message *) *message; - while (isspace(*begin)) { - ++begin; - if (!length--) { - return NULL; - } + if (crlf = strstr(http_line, HTTP_CRLF)) { + line_length = crlf - http_line; + } else { + line_length = strlen(http_line); } - if (new = http_message_parse(begin, length)) { - new->nested = msg; - return new; + if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) { + new = http_message_new(); + + new->parent = old; + *message = new; + *headers = &new->hdrs; + } else { + new = old; + } + + while (isspace(http_line[line_length-1])) --line_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.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."))) { + const char *method_sep_uri = strchr(http_line, ' '); + 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")); + } +} + +#define http_message_init_type _http_message_init_type +static inline void _http_message_init_type(http_message *message, http_message_type type) +{ + switch (message->type = type) + { + case HTTP_MSG_RESPONSE: + message->info.response.http_version = .0; + message->info.response.code = 0; + break; + + case HTTP_MSG_REQUEST: + message->info.request.http_version = .0; + message->info.request.method = NULL; + message->info.request.URI = NULL; + break; + + case HTTP_MSG_NONE: + default: + break; + } +} + +#define http_message_header(m, h) _http_message_header_ex((m), (h), sizeof(h)) +#define http_message_header_ex _http_message_header_ex +static inline zval *_http_message_header_ex(http_message *msg, char *key_str, size_t key_len) +{ + zval **header; + if (SUCCESS == zend_hash_find(&msg->hdrs, key_str, key_len, (void **) &header)) { + return *header; } return NULL; } @@ -53,18 +111,38 @@ PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_mes message = ecalloc(1, sizeof(http_message)); } - message->type = type; - message->nested = NULL; + http_message_init_type(message, type); + message->parent = NULL; phpstr_init(&message->body); zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0); return message; } + +PHP_HTTP_API void _http_message_set_type(http_message *message, http_message_type type) +{ + /* just act if different */ + if (type != message->type) { + + /* free request info */ + 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); + } + } + + /* init */ + http_message_init_type(message, type); + } +} + 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; zend_bool free_msg = msg ? 0 : 1; if (message_length < HTTP_MSG_MIN_SIZE) { @@ -77,144 +155,245 @@ PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char msg = http_message_init(msg); - 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((char *)message, header_length, &msg->hdrs, 1, http_message_parse_headers_callback, (void **) &msg)) { + if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, http_message_headers_cb, (void **) &msg)) { if (free_msg) { http_message_free(msg); } return NULL; } - if (body) { - zval **c; - http_message *nested; + /* header parsing stops at CRLF CRLF */ + if (body = strstr(message, HTTP_CRLF HTTP_CRLF)) { + zval *c; + const char *continue_at = NULL; + + body += lenof(HTTP_CRLF HTTP_CRLF); - if (SUCCESS == zend_hash_find(&msg->hdrs, "Content-Length", sizeof("Content-Length"), (void **) &c)) { - long len = atol(Z_STRVAL_PP(c)); + /* message has content-length header */ + if (c = http_message_header(msg, "Content-Length")) { + long len = atol(Z_STRVAL_P(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; + continue_at = body + len; + } else + + /* message has chunked transfer encoding */ + if (c = http_message_header(msg, "Transfer-Encoding")) { + if (!strcasecmp("chunked", Z_STRVAL_P(c))) { + char *decoded; + size_t decoded_len; + + if (continue_at = http_chunked_decode(body, message + message_length - body, &decoded, &decoded_len)) { + phpstr_from_string_ex(PHPSTR(msg), decoded, decoded_len); + } + } + } else + + /* message has content-range header */ + if (c = http_message_header(msg, "Content-Range")) { + ulong start = 0, end = 0; + + sscanf(Z_STRVAL_P(c), "bytes=%lu-%lu", &start, &end); + if (end > start) { + phpstr_from_string_ex(PHPSTR(msg), body, (size_t) (end - start)); + continue_at = body + (end - start); } - } 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 + + /* no headers that indicate content length */ + if (1) { + phpstr_from_string_ex(PHPSTR(msg), body, message + message_length - body); + } + + /* check for following messages */ + if (continue_at) { + while (isspace(*continue_at)) ++continue_at; + if (continue_at < (message + message_length)) { + http_message *next = NULL, *most = NULL; + + /* set current message to parent of most parent following messages and return deepest */ + if (most = next = http_message_parse(continue_at, message + message_length - continue_at)) { + while (most->parent) most = most->parent; + most->parent = msg; + msg = next; } } - } else { - phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length); } } return msg; } -PHP_HTTP_API void _http_message_parse_headers_callback(void **message, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC) +PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length) { - http_message *old = (http_message *) *message; - http_message *new; + phpstr str; + char *key, *data; + ulong idx; + zval **header; - if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) { - new = http_message_new(); + phpstr_init_ex(&str, 4096, 0); - new->nested = old; - *message = new; - *headers = &new->hdrs; - } else { - new = old; + 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.code); + break; + + case HTTP_MSG_NONE: + default: + break; } - // 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.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."))) { - const char *method_sep_uri = strchr(http_line, ' '); + 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; + } - 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")); + key = NULL; + } + } + + phpstr_appends(&str, HTTP_CRLF); + phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg)); + phpstr_appends(&str, HTTP_CRLF); + + data = phpstr_data(&str, string, length); + if (!string) { + efree(data); } + + phpstr_dtor(&str); } -PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length) +PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length) { + char *buf; + size_t len; phpstr str; - char *key, *data; - ulong idx; - zval **header; - phpstr_init_ex(&str, 4096, 0); + phpstr_init(&str); do { + http_message_tostring(message, &buf, &len); + phpstr_append(&str, buf, len); + efree(buf); + } while (message = message->parent); + + buf = phpstr_data(&str, string, length); + if (!string) { + efree(buf); + } + + phpstr_dtor(&str); +} + +PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC) +{ + STATUS rs = FAILURE; - switch (msg->type) + switch (message->type) + { + case HTTP_MSG_RESPONSE: { - 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.code); - break; + char *key; + ulong idx; + zval **val; + + FOREACH_HASH_KEYVAL(&message->hdrs, key, idx, val) { + if (key) { + char *header; + spprintf(&header, 0, "%s: %s", key, Z_STRVAL_PP(val)); + http_send_header(header); + efree(header); + key = NULL; + } + } + rs = SUCCESS == http_send_status(message->info.response.code) && + SUCCESS == http_send_data(PHPSTR_VAL(message), PHPSTR_LEN(message)) ? + SUCCESS : FAILURE; } + 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_REQUEST: + { +#ifdef HTTP_HAVE_CURL + char *uri = NULL; + zval **zhost, options, headers; + + array_init(&options); + array_init(&headers); + zend_hash_copy(Z_ARRVAL(headers), &message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + add_assoc_zval(&options, "headers", &headers); + + /* check host header */ + if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void **) &zhost)) { + char *colon = NULL, *host = NULL; + size_t host_len = 0; + int port = 0; + + /* check for port */ + if (colon = strchr(Z_STRVAL_PP(zhost), ':')) { + port = atoi(colon + 1); + host = estrndup(Z_STRVAL_PP(zhost), host_len = (Z_STRVAL_PP(zhost) - colon - 1)); + } else { + host = estrndup(Z_STRVAL_PP(zhost), host_len = Z_STRLEN_PP(zhost)); } - - key = NULL; + uri = http_absolute_uri_ex( + message->info.request.URI, strlen(message->info.request.URI), + NULL, 0, host, host_len, port); + efree(host); + } else { + uri = http_absolute_uri(message->info.request.URI); } - } - phpstr_appends(&str, HTTP_CRLF); - phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg)); - phpstr_appends(&str, HTTP_CRLF); + if (!strcasecmp("POST", message->info.request.method)) { + rs = http_post_data(uri, PHPSTR_VAL(message), PHPSTR_LEN(message), Z_ARRVAL(options), NULL, NULL); + } else + if (!strcasecmp("GET", message->info.request.method)) { + rs = http_get(uri, Z_ARRVAL(options), NULL, NULL); + } else + if (!strcasecmp("HEAD", message->info.request.method)) { + rs = http_head(uri, Z_ARRVAL(options), NULL, NULL); + } else { + http_error_ex(E_WARNING, HTTP_E_MSG, + "Cannot send HttpMessage. Request method %s not supported", + message->info.request.method); + } - } while (msg = msg->nested); + efree(uri); +#else + http_error(E_WARNING, HTTP_E_MSG, "HTTP requests not supported - ext/http was not linked against libcurl."); +#endif + } + break; - data = phpstr_data(&str, string, length); - if (!string) { - efree(data); + case HTTP_MSG_NONE: + default: + http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is neither of type HTTP_MSG_REQUEST nor HTTP_MSG_RESPONSE"); + break; } - phpstr_dtor(&str); + return rs; } PHP_HTTP_API void _http_message_dtor(http_message *message) @@ -222,7 +401,7 @@ PHP_HTTP_API void _http_message_dtor(http_message *message) if (message) { zend_hash_destroy(&message->hdrs); phpstr_dtor(PHPSTR(message)); - if (message->type == HTTP_MSG_REQUEST) { + if (HTTP_MSG_TYPE(REQUEST, message)) { if (message->info.request.method) { efree(message->info.request.method); message->info.request.method = NULL; @@ -238,9 +417,9 @@ PHP_HTTP_API void _http_message_dtor(http_message *message) PHP_HTTP_API void _http_message_free(http_message *message) { if (message) { - if (message->nested) { - http_message_free(message->nested); - message->nested = NULL; + if (message->parent) { + http_message_free(message->parent); + message->parent = NULL; } http_message_dtor(message); efree(message); diff --git a/http_message_object.c b/http_message_object.c index 0067151..6ebb751 100644 --- a/http_message_object.c +++ b/http_message_object.c @@ -39,6 +39,7 @@ static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC); zend_class_entry *http_message_object_ce; zend_function_entry http_message_object_fe[] = { + PHP_ME(HttpMessage, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(HttpMessage, getBody, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getHeaders, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setHeaders, NULL, ZEND_ACC_PUBLIC) @@ -53,9 +54,10 @@ zend_function_entry http_message_object_fe[] = { PHP_ME(HttpMessage, setRequestUri, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, getHttpVersion, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, setHttpVersion, NULL, ZEND_ACC_PUBLIC) - PHP_ME(HttpMessage, getNestedMessage, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, getParentMessage, NULL, ZEND_ACC_PUBLIC) + PHP_ME(HttpMessage, send, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, toString, NULL, ZEND_ACC_PUBLIC) - + ZEND_MALIAS(HttpMessage, __toString, toString, NULL, ZEND_ACC_PUBLIC) PHP_ME(HttpMessage, fromString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) @@ -89,11 +91,13 @@ zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message o = ecalloc(1, sizeof(http_message_object)); o->zo.ce = ce; o->message = NULL; + o->parent.handle = 0; + o->parent.handlers = NULL; if (msg) { o->message = msg; - if (msg->nested) { - o->nested = http_message_object_from_msg(msg->nested); + if (msg->parent) { + o->parent = http_message_object_from_msg(msg->parent); } } @@ -117,8 +121,7 @@ static inline void _http_message_object_declare_default_properties(TSRMLS_D) DCL_PROP(PROTECTED, long, responseCode, 0); DCL_PROP_N(PROTECTED, httpVersion); DCL_PROP_N(PROTECTED, headers); - - DCL_PROP_N(PUBLIC, nestedMessage); + DCL_PROP_N(PROTECTED, parentMessage); } static void _http_message_object_free(zend_object *object TSRMLS_DC) @@ -151,15 +154,11 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type return EG(uninitialized_zval_ptr); } - zval_dtor(return_value); - -#if 0 - fprintf(stderr, "Reading property: %s(%d==%d) (%lu)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member)), - zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1) - ); +#if 1 + fprintf(stderr, "Reading property: %s(%d==%d)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member))); #endif - switch (zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1)) + switch (zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1)) { case HTTP_MSG_PROPHASH_TYPE: RETVAL_LONG(msg->type); @@ -168,10 +167,6 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type case HTTP_MSG_PROPHASH_HTTP_VERSION: switch (msg->type) { - case HTTP_MSG_NONE: - RETVAL_NULL(); - break; - case HTTP_MSG_REQUEST: RETVAL_DOUBLE(msg->info.request.http_version); break; @@ -179,6 +174,11 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type case HTTP_MSG_RESPONSE: RETVAL_DOUBLE(msg->info.response.http_version); break; + + case HTTP_MSG_NONE: + default: + RETVAL_NULL(); + break; } break; @@ -192,10 +192,11 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); break; - case HTTP_MSG_PROPHASH_NESTED_MESSAGE: - if (msg->nested) { + case HTTP_MSG_PROPHASH_PARENT_MESSAGE: + if (msg->parent) { + RETVAL_OBJVAL(obj->parent); Z_TYPE_P(return_value) = IS_OBJECT; - return_value->value.obj = obj->nested; + return_value->value.obj = obj->parent; zend_objects_store_add_ref(return_value TSRMLS_CC); } else { RETVAL_NULL(); @@ -203,7 +204,7 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type break; case HTTP_MSG_PROPHASH_REQUEST_METHOD: - if (msg->type == HTTP_MSG_REQUEST && msg->info.request.method) { + if (HTTP_MSG_TYPE(REQUEST, msg) && msg->info.request.method) { RETVAL_STRING(msg->info.request.method, 1); } else { RETVAL_NULL(); @@ -211,7 +212,7 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type break; case HTTP_MSG_PROPHASH_REQUEST_URI: - if (msg->type == HTTP_MSG_REQUEST && msg->info.request.URI) { + if (HTTP_MSG_TYPE(REQUEST, msg) && msg->info.request.URI) { RETVAL_STRING(msg->info.request.URI, 1); } else { RETVAL_NULL(); @@ -219,7 +220,7 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type break; case HTTP_MSG_PROPHASH_RESPONSE_CODE: - if (msg->type == HTTP_MSG_RESPONSE) { + if (HTTP_MSG_TYPE(RESPONSE, msg)) { RETVAL_LONG(msg->info.response.code); } else { RETVAL_NULL(); @@ -243,17 +244,16 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member)); } -#if 0 - fprintf(stderr, "Writing property: %s(%d==%d) (%lu)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member)), - zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1) - ); +#if 1 + fprintf(stderr, "Writing property: %s(%d==%d)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member))); #endif - switch (zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1)) + switch (zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1)) { case HTTP_MSG_PROPHASH_TYPE: + convert_to_long_ex(&value); if (Z_LVAL_P(value) != msg->type) { - if (msg->type == HTTP_MSG_REQUEST) { + if (HTTP_MSG_TYPE(REQUEST, msg)) { if (msg->info.request.method) { efree(msg->info.request.method); } @@ -262,7 +262,7 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va } } msg->type = Z_LVAL_P(value); - if (msg->type == HTTP_MSG_REQUEST) { + if (HTTP_MSG_TYPE(REQUEST, msg)) { msg->info.request.method = NULL; msg->info.request.URI = NULL; } @@ -271,6 +271,7 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va break; case HTTP_MSG_PROPHASH_HTTP_VERSION: + convert_to_long_ex(&value); switch (msg->type) { case HTTP_MSG_REQUEST: @@ -284,27 +285,30 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va break; case HTTP_MSG_PROPHASH_BODY: + convert_to_string_ex(&value); phpstr_dtor(PHPSTR(msg)); phpstr_from_string_ex(PHPSTR(msg), Z_STRVAL_P(value), Z_STRLEN_P(value)); break; case HTTP_MSG_PROPHASH_HEADERS: + convert_to_array_ex(&value); zend_hash_clean(&msg->hdrs); zend_hash_copy(&msg->hdrs, Z_ARRVAL_P(value), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); break; - case HTTP_MSG_PROPHASH_NESTED_MESSAGE: - if (msg->nested) { + case HTTP_MSG_PROPHASH_PARENT_MESSAGE: + if (msg->parent) { zval tmp; - tmp.value.obj = obj->nested; + tmp.value.obj = obj->parent; zend_objects_store_del_ref(&tmp TSRMLS_CC); } zend_objects_store_add_ref(value TSRMLS_CC); - obj->nested = value->value.obj; + obj->parent = value->value.obj; break; case HTTP_MSG_PROPHASH_REQUEST_METHOD: - if (msg->type == HTTP_MSG_REQUEST) { + convert_to_string_ex(&value); + if (HTTP_MSG_TYPE(REQUEST, msg)) { if (msg->info.request.method) { efree(msg->info.request.method); } @@ -313,7 +317,8 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va break; case HTTP_MSG_PROPHASH_REQUEST_URI: - if (msg->type == HTTP_MSG_REQUEST) { + convert_to_string_ex(&value); + if (HTTP_MSG_TYPE(REQUEST, msg)) { if (msg->info.request.URI) { efree(msg->info.request.URI); } @@ -322,7 +327,8 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va break; case HTTP_MSG_PROPHASH_RESPONSE_CODE: - if (msg->type == HTTP_MSG_RESPONSE) { + convert_to_long_ex(&value); + if (HTTP_MSG_TYPE(RESPONSE, msg)) { msg->info.response.code = Z_LVAL_P(value); } break; diff --git a/http_methods.c b/http_methods.c index 1440b13..e06f340 100644 --- a/http_methods.c +++ b/http_methods.c @@ -547,6 +547,30 @@ PHP_METHOD(HttpMessage, fromString) } /* }}} */ +/* {{{ proto void HttpMessage::__construct([string message]) + * + * Instantiate a new HttpMessage object. + */ +PHP_METHOD(HttpMessage, __construct) +{ + char *message = NULL; + int length = 0; + getObject(http_message_object, obj); + + SET_EH_THROW_HTTP(); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) { + if (obj->message = http_message_parse(message, length)) { + if (obj->message->parent) { + obj->parent = http_message_object_from_msg(obj->message->parent); + } + } + } else if (!obj->message) { + obj->message = http_message_new(); + } + SET_EH_NORMAL(); +} +/* }}} */ + /* {{{ proto string HttpMessage::getBody() * * Get the body of the parsed Message. @@ -647,21 +671,7 @@ PHP_METHOD(HttpMessage, setType) if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) { return; } - if (type != obj->message->type) { - if (obj->message->type == HTTP_MSG_REQUEST) { - if (obj->message->info.request.method) { - efree(obj->message->info.request.method); - } - if (obj->message->info.request.URI) { - efree(obj->message->info.request.URI); - } - } - obj->message->type = type; - if (obj->message->type == HTTP_MSG_REQUEST) { - obj->message->info.request.method = NULL; - obj->message->info.request.URI = NULL; - } - } + http_message_set_type(obj->message, type); } /* }}} */ @@ -675,7 +685,7 @@ PHP_METHOD(HttpMessage, getResponseCode) NO_ARGS; - if (obj->message->type != HTTP_MSG_RESPONSE) { + if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) { http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE"); RETURN_NULL(); } @@ -828,7 +838,7 @@ PHP_METHOD(HttpMessage, setRequestUri) PHP_METHOD(HttpMessage, getHttpVersion) { char ver[4] = {0}; - float *version; + float version; getObject(http_message_object, obj); NO_ARGS; @@ -836,16 +846,18 @@ PHP_METHOD(HttpMessage, getHttpVersion) switch (obj->message->type) { case HTTP_MSG_RESPONSE: - version = &obj->message->info.response.http_version; + version = obj->message->info.response.http_version; break; + case HTTP_MSG_REQUEST: - version = &obj->message->info.request.http_version; + version = obj->message->info.request.http_version; break; + case HTTP_MSG_NONE: default: RETURN_NULL(); } - sprintf(ver, "1.1f", version); + sprintf(ver, "%1.1f", version); RETURN_STRINGL(ver, 3, 1); } /* }}} */ @@ -886,28 +898,39 @@ PHP_METHOD(HttpMessage, setHttpVersion) } /* }}} */ -/* {{{ proto HttpMessage HttpMessage::getNestedMessage() +/* {{{ proto HttpMessage HttpMessage::getParentMessage() * - * Get nested Message. + * Get parent Message. */ -PHP_METHOD(HttpMessage, getNestedMessage) +PHP_METHOD(HttpMessage, getParentMessage) { getObject(http_message_object, obj); NO_ARGS; - if (obj->message->nested) { - Z_TYPE_P(return_value) = IS_OBJECT; - return_value->value.obj = obj->nested; - return_value->is_ref = 1; - zend_objects_store_add_ref(return_value TSRMLS_CC); + if (obj->message->parent) { + RETVAL_OBJVAL(obj->parent); } else { RETVAL_NULL(); } } /* }}} */ -/* {{{ proto string HttpMessage::toString() +/* {{{ proto bool HttpMessage::send() + * + * Send the Message according to its type as Response or Request. + */ +PHP_METHOD(HttpMessage, send) +{ + getObject(http_message_object, obj); + + NO_ARGS; + + RETURN_SUCCESS(http_message_send(obj->message)); +} +/* }}} */ + +/* {{{ proto string HttpMessage::toString([bool include_parent = true]) * * Get the string representation of the Message. */ @@ -915,11 +938,18 @@ PHP_METHOD(HttpMessage, toString) { char *string; size_t length; + zend_bool include_parent = 1; getObject(http_message_object, obj); - NO_ARGS; + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) { + RETURN_FALSE; + } - http_message_tostring(obj->message, &string, &length); + if (include_parent) { + http_message_serialize(obj->message, &string, &length); + } else { + http_message_tostring(obj->message, &string, &length); + } RETURN_STRINGL(string, length, 0); } /* }}} */ diff --git a/php_http_api.h b/php_http_api.h index 27e0bab..d4fb508 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -46,7 +46,7 @@ extern STATUS _http_check_method(const char *method, const char *methods); PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_size, zend_bool check TSRMLS_DC); #define http_chunked_decode(e, el, d, dl) _http_chunked_decode((e), (el), (d), (dl) TSRMLS_CC) -PHP_HTTP_API char *_http_chunked_decode(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC); +PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC); #define http_split_response(r, h, b) _http_split_response((r), (h), (b) TSRMLS_CC) PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC); diff --git a/php_http_headers_api.h b/php_http_headers_api.h index 7907b62..f831ccd 100644 --- a/php_http_headers_api.h +++ b/php_http_headers_api.h @@ -26,16 +26,15 @@ typedef enum { RANGE_ERR } http_range_status; -typedef void (*http_parse_headers_callback_t)(void **callback_data, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC); +typedef void (*http_parse_headers_callback_t)(const char *http_line, HashTable **headers, void **callback_data TSRMLS_DC); #define http_parse_headers_default_callback _http_parse_headers_default_callback -PHP_HTTP_API void _http_parse_headers_default_callback(void **cb_data, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC); +PHP_HTTP_API void _http_parse_headers_default_callback(const char *http_line, HashTable **headers, void **cb_data TSRMLS_DC); -#define http_parse_headers(h, l, a) _http_parse_headers_ex((h), (l), Z_ARRVAL_P(a), 1, _http_parse_headers_default_callback, NULL TSRMLS_CC) -#define http_parse_headers_ex(h, l, ht, p) _http_parse_headers_ex((h), (l), (ht), (p), _http_parse_headers_default_callback, NULL TSRMLS_CC) -#define http_parse_headers_cb(h, l, ht, p, f, d) _http_parse_headers_ex((h), (l), (ht), (p), (f), (d) TSRMLS_CC) -PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len, HashTable *headers, zend_bool prettify, - http_parse_headers_callback_t func, void *callback_data TSRMLS_DC); +#define http_parse_headers(h, a) _http_parse_headers_ex((h), Z_ARRVAL_P(a), 1, _http_parse_headers_default_callback, NULL TSRMLS_CC) +#define http_parse_headers_ex(h, ht, p) _http_parse_headers_ex((h), (ht), (p), _http_parse_headers_default_callback, NULL TSRMLS_CC) +#define http_parse_headers_cb(h, ht, p, f, d) _http_parse_headers_ex((h), (ht), (p), (f), (d) TSRMLS_CC) +PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_parse_headers_callback_t func, void *callback_data TSRMLS_DC); #define http_parse_cookie(c, ht) _http_parse_cookie((c), (ht) TSRMLS_CC) PHP_HTTP_API STATUS _http_parse_cookie(const char *cookie, HashTable *values TSRMLS_DC); diff --git a/php_http_message_api.h b/php_http_message_api.h index d60dc98..d529a0a 100644 --- a/php_http_message_api.h +++ b/php_http_message_api.h @@ -18,19 +18,7 @@ #ifndef PHP_HTTP_MESSAGE_API_H #define PHP_HTTP_MESSAGE_API_H -/* -DUMP: -HttpMessage - ->toResponseString(); - ->toRequestString(); - ->__toString(); ->__sleep(); ->serialize(); - ->fromString(); __wakeup($message); ->unserialize(); - ->setStatusCode(); - ->setHeader(); ->addHeader()... -*/ - #include "phpstr/phpstr.h" -#include "php_http_headers_api.h" typedef enum { HTTP_MSG_NONE, @@ -59,26 +47,36 @@ struct _http_message { } info; - http_message *nested; + http_message *parent; }; /* required minimum length of an HTTP message "HTTP/1.1 200\r\n" */ #define HTTP_MSG_MIN_SIZE 15 +/* shorthand for type checks */ +#define HTTP_MSG_TYPE(TYPE, msg) ((msg) && ((msg)->type == HTTP_MSG_ ##TYPE)) + #define http_message_new() _http_message_init_ex(NULL, 0) #define http_message_init(m) _http_message_init_ex((m), 0) #define http_message_init_ex(m, t) _http_message_init_ex((m), (t)) PHP_HTTP_API http_message *_http_message_init_ex(http_message *m, http_message_type t); +#define http_message_set_type(m, t) _http_message_set_type((m), (t)) +PHP_HTTP_API void _http_message_set_type(http_message *m, http_message_type t); + #define http_message_parse(m, l) http_message_parse_ex(NULL, (m), (l)) #define http_message_parse_ex(h, m, l) _http_message_parse_ex((h), (m), (l) TSRMLS_CC) PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t length TSRMLS_DC); -#define http_message_parse_headers_callback _http_message_parse_headers_callback -PHP_HTTP_API void _http_message_parse_headers_callback(void *message, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC); - #define http_message_tostring(m, s, l) _http_message_tostring((m), (s), (l)) PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length); + +#define http_message_serialize(m, s, l) _http_message_serialize((m), (s), (l)) +PHP_HTTP_API void _http_message_serialize(http_message *message, char **string, size_t *length); + +#define http_message_send(m) _http_message_send((m) TSRMLS_CC) +PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC); + #define http_message_dtor(m) _http_message_dtor((m)) PHP_HTTP_API void _http_message_dtor(http_message *message); diff --git a/php_http_message_object.h b/php_http_message_object.h index 8a0bcad..6bc5b39 100644 --- a/php_http_message_object.h +++ b/php_http_message_object.h @@ -24,7 +24,7 @@ typedef struct { zend_object zo; http_message *message; - zend_object_value nested; + zend_object_value parent; } http_message_object; extern zend_class_entry *http_message_object_ce; @@ -46,11 +46,26 @@ extern void _http_message_object_free(zend_object *object TSRMLS_DC); #define HTTP_MSG_PROPHASH_BODY 254474387LU #define HTTP_MSG_PROPHASH_HEADERS 3199929089LU #define HTTP_MSG_PROPHASH_NESTED_MESSAGE 3652857165LU +#define HTTP_MSG_PROPHASH_PARENT_MESSAGE 0LU #define HTTP_MSG_PROPHASH_REQUEST_METHOD 1669022159LU #define HTTP_MSG_PROPHASH_REQUEST_URI 3208695486LU #define HTTP_MSG_PROPHASH_RESPONSE_STATUS 3857097400LU #define HTTP_MSG_PROPHASH_RESPONSE_CODE 1305615119LU +#define HTTP_MSG_CHECK_OBJ(obj, dofail) \ + if (!(obj)->message) { \ + http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is empty"); \ + dofail; \ + } +#define HTTP_MSG_CHECK_STD() HTTP_MSG_CHECK_OBJ(obj, RETURN_FALSE) + +#define HTTP_MSG_INIT_OBJ(obj) \ + if (!(obj)->message) { \ + (obj)->message = http_message_new(); \ + } +#define HTTP_MSG_INIT_STD() HTTP_MSG_INIT_OBJ(obj) + +PHP_METHOD(HttpMessage, __construct); PHP_METHOD(HttpMessage, getBody); PHP_METHOD(HttpMessage, getHeaders); PHP_METHOD(HttpMessage, setHeaders); @@ -65,7 +80,8 @@ PHP_METHOD(HttpMessage, getRequestUri); PHP_METHOD(HttpMessage, setRequestUri); PHP_METHOD(HttpMessage, getHttpVersion); PHP_METHOD(HttpMessage, setHttpVersion); -PHP_METHOD(HttpMessage, getNestedMessage); +PHP_METHOD(HttpMessage, getParentMessage); +PHP_METHOD(HttpMessage, send); PHP_METHOD(HttpMessage, toString); PHP_METHOD(HttpMessage, fromString); diff --git a/php_http_std_defs.h b/php_http_std_defs.h index 953d4ac..c9369b5 100644 --- a/php_http_std_defs.h +++ b/php_http_std_defs.h @@ -31,7 +31,25 @@ typedef int STATUS; #define lenof(S) (sizeof(S) - 1) /* return bool (v == SUCCESS) */ +#define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v)) #define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v)) +/* return object(values) */ +#define RETVAL_OBJECT(o) \ + return_value->is_ref = 1; \ + return_value->type = IS_OBJECT; \ + return_value->value.obj = (o)->value.obj; \ + zval_add_ref(&return_value) +#define RETURN_OBJECT(o) \ + RETVAL_OBJECT(o); \ + return +#define RETVAL_OBJVAL(ov) \ + return_value->is_ref = 1; \ + return_value->type = IS_OBJECT; \ + return_value->value.obj = (ov); \ + zend_objects_store_add_ref(return_value TSRMLS_CC) +#define RETURN_OBJVAL(ov) \ + RETVAL_OBJVAL(ov); \ + return /* function accepts no args */ #define NO_ARGS \ -- 2.30.2