flush
authorMichael Wallner <mike@php.net>
Mon, 2 May 2005 20:58:00 +0000 (20:58 +0000)
committerMichael Wallner <mike@php.net>
Mon, 2 May 2005 20:58:00 +0000 (20:58 +0000)
14 files changed:
CREDITS
http.c
http_api.c
http_curl_api.c
http_functions.c
http_headers_api.c
http_message_api.c
http_message_object.c
http_methods.c
php_http_api.h
php_http_headers_api.h
php_http_message_api.h
php_http_message_object.h
php_http_std_defs.h

diff --git a/CREDITS b/CREDITS
index a02e710..1b486cb 100644 (file)
--- 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 (file)
--- 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);
index e76846c..da469a9 100644 (file)
@@ -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);
 }
 /* }}} */
 
index 7938573..e2d5911 100644 (file)
@@ -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; \
        }
index 5854e30..9bf3399 100644 (file)
@@ -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)
  * <?php
  * array(
  *     0 => 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();
 }
 
 /*
index 09673e9..fad18e4 100644 (file)
@@ -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);
        }
 }
 
index dd2cfff..1c977bf 100644 (file)
 #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);
index 0067151..6ebb751 100644 (file)
@@ -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;
index 1440b13..e06f340 100644 (file)
@@ -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);
 }
 /* }}} */
index 27e0bab..d4fb508 100644 (file)
@@ -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);
index 7907b62..f831ccd 100644 (file)
@@ -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);
index d60dc98..d529a0a 100644 (file)
 #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);
 
index 8a0bcad..6bc5b39 100644 (file)
@@ -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);
index 953d4ac..c9369b5 100644 (file)
@@ -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 \