- ditch http_split_response()
authorMichael Wallner <mike@php.net>
Tue, 23 Aug 2005 18:14:11 +0000 (18:14 +0000)
committerMichael Wallner <mike@php.net>
Tue, 23 Aug 2005 18:14:11 +0000 (18:14 +0000)
- unify parsing of HTTP pre-header line; add info api
- add several log facilities through http_exit()
- several other fixbits

# unfinished...

31 files changed:
config.m4
config.w32
http.c
http.dsp
http_api.c
http_cache_api.c
http_functions.c
http_headers_api.c
http_info_api.c [new file with mode: 0644]
http_message_api.c
http_message_object.c
http_request_api.c
http_request_object.c
http_response_object.c
http_send_api.c
http_url_api.c
http_util_object.c
missing.c
php_http.h
php_http_api.h
php_http_cache_api.h
php_http_headers_api.h
php_http_info_api.h [new file with mode: 0644]
php_http_message_api.h
php_http_send_api.h
php_http_std_defs.h
php_http_util_object.h
phpstr/phpstr.c
phpstr/phpstr.h
tests/split_response_001.phpt [deleted file]
tests/split_response_002.phpt [deleted file]

index 85b6de3..de29b53 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -75,7 +75,8 @@ dnl ----
                http_util_object.c http_message_object.c http_request_object.c http_request_pool_api.c \
                http_response_object.c http_exception_object.c http_requestpool_object.c \
                http_api.c http_auth_api.c http_cache_api.c http_request_api.c http_date_api.c \
-               http_headers_api.c http_message_api.c http_send_api.c http_url_api.c"
+               http_headers_api.c http_message_api.c http_send_api.c http_url_api.c \
+               http_info_api.c"
        PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, [$ext_shared])
        PHP_ADD_BUILD_DIR($ext_builddir/phpstr, 1)
        PHP_SUBST([HTTP_SHARED_LIBADD])
index c705296..941ca4d 100644 (file)
@@ -10,7 +10,8 @@ if (PHP_HTTP != "no") {
                "http_request_object.c http_response_object.c "+
                "http_api.c http_auth_api.c http_cache_api.c http_request_pool_api.c "+
                "http_request_api.c http_date_api.c http_headers_api.c "+
-               "http_message_api.c http_send_api.c http_url_api.c ",
+               "http_message_api.c http_send_api.c http_url_api.c "+
+               "http_info_api.c",
                null,
                "/I\"" + configure_module_dirname + "/phpstr\"");
        ADD_SOURCES(configure_module_dirname + "/phpstr", "phpstr.c", "http");
diff --git a/http.c b/http.c
index 2ecaa58..444341e 100644 (file)
--- a/http.c
+++ b/http.c
@@ -84,7 +84,6 @@ function_entry http_functions[] = {
        PHP_FE(http_send_stream, NULL)
        PHP_FE(http_chunked_decode, NULL)
        PHP_FE(http_parse_message, NULL)
-       PHP_FE(http_split_response, NULL)
        PHP_FE(http_parse_headers, NULL)
        PHP_FE(http_get_request_headers, NULL)
        PHP_FE(http_get_request_body, NULL)
@@ -184,6 +183,9 @@ PHP_INI_MH(http_update_allowed_methods)
 PHP_INI_BEGIN()
        HTTP_PHP_INI_ENTRY("http.allowed_methods", "", PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed)
        HTTP_PHP_INI_ENTRY("http.cache_log", "", PHP_INI_ALL, OnUpdateString, log.cache)
+       HTTP_PHP_INI_ENTRY("http.redirect_log", "", PHP_INI_ALL, OnUpdateString, log.redirect)
+       HTTP_PHP_INI_ENTRY("http.allowed_methods_log", "", PHP_INI_ALL, OnUpdateString, log.allowed_methods)
+       HTTP_PHP_INI_ENTRY("http.composite_log", "", PHP_INI_ALL, OnUpdateString, log.composite)
 #ifdef ZEND_ENGINE_2
        HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions)
 #endif
@@ -319,8 +321,8 @@ PHP_MINFO_FUNCTION(http)
                php_info_print_table_row(2, "Custom Request Methods:",
                        PHPSTR_LEN(custom_request_methods) ? PHPSTR_VAL(custom_request_methods) : "none registered");
 
-               phpstr_free(known_request_methods);
-               phpstr_free(custom_request_methods);
+               phpstr_free(&known_request_methods);
+               phpstr_free(&custom_request_methods);
        }
        php_info_print_table_end();
 #endif
index 7ccd176..b41373e 100644 (file)
--- a/http.dsp
+++ b/http.dsp
@@ -138,6 +138,10 @@ SOURCE=.\http_url_api.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\http_info_api.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\phpstr\phpstr.c\r
 # End Source File\r
 # End Group\r
@@ -186,6 +190,10 @@ SOURCE=.\php_http_url_api.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\php_http_info_api.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\php_http_std_defs.h\r
 # End Source File\r
 # Begin Source File\r
index de95a88..654bf88 100644 (file)
@@ -38,7 +38,7 @@
 
 ZEND_EXTERN_MODULE_GLOBALS(http);
 
-/* char *pretty_key(char *, size_t, zend_bool, zebd_bool) */
+/* char *pretty_key(char *, size_t, zend_bool, zend_bool) */
 char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
 {
        if (key && key_len) {
@@ -179,19 +179,53 @@ void _http_error_ex(long type, long code, const char *format, ...)
 }
 /* }}} */
 
-/* {{{ STATUS http_exit(int, char*) */
-STATUS _http_exit_ex(int status, char *header, zend_bool free_header TSRMLS_DC)
+/* {{{ STATUS http_exit(int, char*, char*, zend_bool) */
+STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC)
 {
-       if (SUCCESS != http_send_status_header(status, header)) {
+       char datetime[128];
+       
+       if (SUCCESS != http_send_status_header(status, send_header ? header : NULL)) {
                http_error_ex(HE_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, header ? header : "");
-               if (free_header && header) {
-                       efree(header);
-               }
+               STR_FREE(header);
+               STR_FREE(body);
                return FAILURE;
        }
-       if (free_header && header) {
-               efree(header);
+       if (body) {
+               PHPWRITE(body, strlen(body));
+       }
+       {
+               time_t now;
+               struct tm nowtm;
+               
+               time(&now);
+               strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
+       }
+
+#define HTTP_LOG_WRITE(for, type, header) \
+       HTTP_LOG_WRITE_EX(for, type, header); \
+       HTTP_LOG_WRITE_EX(composite, type, header);
+
+#define HTTP_LOG_WRITE_EX(for, type, header) \
+       if (HTTP_G(log).##for && strlen(HTTP_G(log).##for)) { \
+               php_stream *log = php_stream_open_wrapper(HTTP_G(log).##for, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL); \
+                \
+               if (log) { \
+                       php_stream_printf(log TSRMLS_CC, "%s [%12s] %32s <%s>%s", datetime, type, header, SG(request_info).request_uri, PHP_EOL); \
+                       php_stream_close(log); \
+               } \
+        \
        }
+       switch (status)
+       {
+               case 301:       HTTP_LOG_WRITE(redirect, "301-REDIRECT", header);                       break;
+               case 302:       HTTP_LOG_WRITE(redirect, "302-REDIRECT", header);                       break;
+               case 304:       HTTP_LOG_WRITE(cache, "304-CACHE", header);                                     break;
+               case 401:       HTTP_LOG_WRITE(auth, "401-AUTH", header);                                       break;
+               case 403:       HTTP_LOG_WRITE(auth, "403-AUTH", header);                                       break;
+               case 405:       HTTP_LOG_WRITE(allowed_methods, "405-ALLOWED", header);         break;
+       }
+       STR_FREE(header);
+       STR_FREE(body);
        zend_bailout();
        /* fake */
        return SUCCESS;
@@ -218,7 +252,7 @@ PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_size, zen
        zval **hsv;
        zval **var;
        
-       if (SUCCESS != zend_hash_find(&EG(symbol_table), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), (void **) &hsv)) {
+       if (SUCCESS != zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &hsv)) {
                return NULL;
        }
        if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(hsv), (char *) key, key_size, (void **) &var)) {
@@ -306,29 +340,8 @@ PHP_HTTP_API const char *_http_chunked_decode(const char *encoded, size_t encode
 }
 /* }}} */
 
-/* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
-PHP_HTTP_API STATUS _http_split_response(char *response, size_t response_len,
-       HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
-{
-       char *header = response, *real_body = NULL;
-
-       while (0 < (response_len - (response - header + 4))) {
-               if (    (*response++ == '\r') &&
-                               (*response++ == '\n') &&
-                               (*response++ == '\r') &&
-                               (*response++ == '\n')) {
-                       real_body = response;
-                       break;
-               }
-       }
-
-       if (real_body && (*body_len = (response_len - (real_body - header)))) {
-               *body = ecalloc(1, *body_len + 1);
-               memcpy(*body, real_body, *body_len);
-       }
-
-       return http_parse_headers_ex(header, headers, 1);
-}
+/* {{{ STATUS http_locate_body(char *, size_t) */
+PHP_HTTP_API 
 /* }}} */
 
 /*
index 109a568..52d76ea 100644 (file)
 
 ZEND_EXTERN_MODULE_GLOBALS(http);
 
-/* {{{ STATUS http_cache_exit(char *, zend_bool) */
-STATUS _http_cache_exit_ex(char *cache_token, zend_bool etag, zend_bool free_token TSRMLS_DC)
-{
-       if (HTTP_G(log).cache && strlen(HTTP_G(log).cache)) {
-               php_stream *log = php_stream_open_wrapper(HTTP_G(log).cache, "ab", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
-
-               if (log) {
-                       time_t now;
-                       struct tm nowtm;
-                       char datetime[128];
-
-                       time(&now);
-                       strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", php_localtime_r(&now, &nowtm));
-                       php_stream_printf(log TSRMLS_CC, "%s [%s] %32s %s\n", datetime, etag ? "ETAG":"LMOD", cache_token, SG(request_info).request_uri);
-                       php_stream_close(log);
-               }
-       }
-       if (free_token && cache_token) {
-               efree(cache_token);
-       }
-       return http_exit_ex(304, NULL, 0);
-}
-/* }}} */
-
 /* {{{ char *http_etag(void *, size_t, http_send_mode) */
 PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC)
 {
@@ -170,16 +146,20 @@ PHP_HTTP_API zend_bool _http_match_etag_ex(const char *entry, const char *etag,
 PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified,
        time_t send_modified, const char *cache_control, size_t cc_len TSRMLS_DC)
 {
+       char *sent_header = NULL;
+       
        if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) {
                return FAILURE;
        }
 
-       if (SUCCESS != http_send_last_modified(send_modified)) {
+       if (SUCCESS != http_send_last_modified_ex(send_modified, &sent_header)) {
                return FAILURE;
        }
 
        if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", last_modified)) {
-               return http_cache_exit(http_date(last_modified), 0);
+               http_exit_ex(304, sent_header, NULL, 0);
+       } else {
+               STR_FREE(sent_header);
        }
 
        return SUCCESS;
@@ -190,18 +170,22 @@ PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified,
 PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len,
        const char *cache_control, size_t cc_len TSRMLS_DC)
 {
+       char *sent_header = NULL;
+       
        if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) {
                return FAILURE;
        }
 
        if (etag_len) {
-               if (SUCCESS != http_send_etag(etag, etag_len)) {
+               if (SUCCESS != http_send_etag_ex(etag, etag_len, &sent_header)) {
                        return FAILURE;
                }
-               if (!http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
-                       return SUCCESS;
+               if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
+                       http_exit_ex(304, sent_header, NULL, 0);
+               } else {
+                       STR_FREE(sent_header);
                }
-               return http_cache_exit_ex((char *)etag, 1, 0);
+               return SUCCESS;
        }
 
        /* if no etag is given and we didn't already start ob_etaghandler -- start it */
@@ -236,12 +220,16 @@ PHP_HTTP_API void _http_ob_etaghandler(char *output, uint output_len,
 
                /* just do that if desired */
                if (HTTP_G(etag).started) {
+                       char *sent_header = NULL;
+                       
                        make_digest(etag, digest);
                        http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
-                       http_send_etag(etag, 32);
+                       http_send_etag_ex(etag, 32, &sent_header);
 
                        if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
-                               http_cache_exit_ex(etag, 1, 0);
+                               http_exit_ex(304, sent_header, NULL, 0);
+                       } else {
+                               STR_FREE(sent_header);
                        }
                }
        }
index ae27b5e..ced4e81 100644 (file)
@@ -461,9 +461,7 @@ PHP_FUNCTION(http_redirect)
        size_t query_len = 0;
        zend_bool session = 0, permanent = 0, free_params = 0;
        zval *params = NULL;
-       char *query = NULL, *url = NULL, *URI,
-               LOC[HTTP_URI_MAXLEN + sizeof("Location: ")],
-               RED[HTTP_URI_MAXLEN * 2 + sizeof("Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n")];
+       char *query = NULL, *url = NULL, *URI, *LOC, *RED = NULL;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
                RETURN_FALSE;
@@ -527,11 +525,15 @@ PHP_FUNCTION(http_redirect)
        URI = http_absolute_uri(url);
 
        if (query_len) {
-               snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s?%s", URI, query);
-               sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
+               spprintf(&LOC, 0, "Location: %s?%s", URI, query);
+               if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
+                       spprintf(&RED, 0, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, query, URI, query);
+               }
        } else {
-               snprintf(LOC, HTTP_URI_MAXLEN + sizeof("Location: "), "Location: %s", URI);
-               sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
+               spprintf(&LOC, 0, "Location: %s", URI);
+               if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
+                       spprintf(&RED, 0, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
+               }
        }
        
        efree(URI);
@@ -543,13 +545,7 @@ PHP_FUNCTION(http_redirect)
                FREE_ZVAL(params);
        }
 
-       if ((SUCCESS == http_send_header_string(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
-               if (SG(request_info).request_method && strcmp(SG(request_info).request_method, "HEAD")) {
-                       PHPWRITE(RED, strlen(RED));
-               }
-               RETURN_TRUE;
-       }
-       RETURN_FALSE;
+       RETURN_SUCCESS(http_exit_ex(permanent ? 301 : 302, LOC, RED, 1));
 }
 /* }}} */
 
@@ -633,90 +629,6 @@ PHP_FUNCTION(http_chunked_decode)
 }
 /* }}} */
 
-/* {{{ proto array http_split_response(string http_response)
- *
- * This function splits an HTTP response into an array with headers and the
- * content body. The returned array may look simliar to the following example:
- *
- * <pre>
- * <?php
- * array(
- *     0 => array(
- *         'Response Status' => '200 Ok',
- *         'Content-Type' => 'text/plain',
- *         'Content-Language' => 'en-US'
- *     ),
- *     1 => "Hello World!"
- * );
- * ?>
- * </pre>
- */
-PHP_FUNCTION(http_split_response)
-{
-       char *response, *body;
-       int response_len;
-       size_t body_len;
-       zval *zheaders;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &response, &response_len) != SUCCESS) {
-               RETURN_FALSE;
-       }
-
-       MAKE_STD_ZVAL(zheaders);
-       array_init(zheaders);
-
-       if (SUCCESS != http_split_response(response, response_len, Z_ARRVAL_P(zheaders), &body, &body_len)) {
-               RETURN_FALSE;
-       }
-
-       array_init(return_value);
-       add_index_zval(return_value, 0, zheaders);
-       add_index_stringl(return_value, 1, body, body_len, 0);
-}
-/* }}} */
-
-static void http_message_toobject_recursive(http_message *msg, zval *obj TSRMLS_DC)
-{
-       zval *headers;
-       
-       add_property_long(obj, "type", msg->type);
-       switch (msg->type)
-       {
-               case HTTP_MSG_RESPONSE:
-                       add_property_double(obj, "httpVersion", msg->info.response.http_version);
-                       add_property_long(obj, "responseCode", msg->info.response.code);
-               break;
-               
-               case HTTP_MSG_REQUEST:
-                       add_property_double(obj, "httpVersion", msg->info.request.http_version);
-                       add_property_string(obj, "requestMethod", msg->info.request.method, 1);
-                       add_property_string(obj, "requestUri", msg->info.request.URI, 1);
-               break;
-       }
-       
-       MAKE_STD_ZVAL(headers);
-       array_init(headers);
-       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
-       add_property_zval(obj, "headers", headers);
-       zval_ptr_dtor(&headers);
-       
-       add_property_stringl(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
-       
-       if (msg->parent) {
-               zval *parent;
-               
-               MAKE_STD_ZVAL(parent);
-               object_init(parent);
-               add_property_zval(obj, "parentMessage", parent);
-               http_message_toobject_recursive(msg->parent, parent TSRMLS_CC);
-               zval_ptr_dtor(&parent);
-       } else {
-               add_property_null(obj, "parentMessage");
-       }
-       http_message_dtor(msg);
-       efree(msg);
-}
-
 /* {{{ proto object http_parse_message(string message)
  *
  * Parses (a) http_message(s) into a simple recursive object structure:
@@ -766,7 +678,7 @@ PHP_FUNCTION(http_parse_message)
        
        if (msg = http_message_parse(message, message_len)) {
                object_init(return_value);
-               http_message_toobject_recursive(msg, return_value TSRMLS_CC);
+               http_message_tostruct_recursive(msg, return_value);
        } else {
                RETURN_NULL();
        }
@@ -908,7 +820,6 @@ PHP_FUNCTION(http_match_request_header)
  *     'content_type' => 'text/html; charset=iso-8859-1',
  *     'redirect_time' => 0,
  *     'redirect_count' => 0,
- *     'private' => '',
  *     'http_connectcode' => 0,
  *     'httpauth_avail' => 0,
  *     'proxyauth_avail' => 0,
@@ -934,7 +845,7 @@ PHP_FUNCTION(http_get)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_get(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETURN_PHPSTR_VAL(response);
+               RETURN_PHPSTR_VAL(&response);
        } else {
                RETURN_FALSE;
        }
@@ -965,14 +876,14 @@ PHP_FUNCTION(http_head)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_head(URL, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETURN_PHPSTR_VAL(response);
+               RETURN_PHPSTR_VAL(&response);
        } else {
                RETURN_FALSE;
        }
 }
 /* }}} */
 
-/* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
+/* {{{ proto string http_post_data(string url, string data[, array options[, array &info]])
  *
  * Performs an HTTP POST request, posting data.
  * Returns the HTTP response as string.
@@ -1001,7 +912,7 @@ PHP_FUNCTION(http_post_data)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETVAL_PHPSTR_VAL(response);
+               RETVAL_PHPSTR_VAL(&response);
        } else {
                RETVAL_FALSE;
        }
@@ -1037,7 +948,7 @@ PHP_FUNCTION(http_post_fields)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_post(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETVAL_PHPSTR_VAL(response);
+               RETVAL_PHPSTR_VAL(&response);
        } else {
                RETVAL_FALSE;
        }
@@ -1084,7 +995,7 @@ PHP_FUNCTION(http_put_file)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETVAL_PHPSTR_VAL(response);
+               RETVAL_PHPSTR_VAL(&response);
        } else {
                RETVAL_FALSE;
        }
@@ -1128,7 +1039,7 @@ PHP_FUNCTION(http_put_stream)
 
        phpstr_init_ex(&response, HTTP_CURLBUF_SIZE, 0);
        if (SUCCESS == http_put(URL, &body, options ? Z_ARRVAL_P(options) : NULL, info ? Z_ARRVAL_P(info) : NULL, &response)) {
-               RETURN_PHPSTR_VAL(response);
+               RETURN_PHPSTR_VAL(&response);
        } else {
                RETURN_NULL();
        }
@@ -1381,12 +1292,12 @@ PHP_FUNCTION(http_build_query)
 
        formstr = phpstr_new();
        if (SUCCESS != http_urlencode_hash_implementation_ex(HASH_OF(formdata), formstr, arg_sep, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL))) {
-               phpstr_free(formstr);
+               phpstr_free(&formstr);
                RETURN_FALSE;
        }
 
        if (!formstr->used) {
-               phpstr_free(formstr);
+               phpstr_free(&formstr);
                RETURN_NULL();
        }
 
@@ -1398,6 +1309,13 @@ PHP_FUNCTION(http_build_query)
 
 PHP_FUNCTION(http_test)
 {
+       ulong idx;
+       char *key;
+       zval **data;
+       FOREACH_HASH_KEYVAL(&EG(symbol_table), key, idx, data) {
+               convert_to_string_ex(data);
+               fprintf(stderr, "\t %s => %s\n", key, Z_STRVAL_PP(data));
+       }
 }
 
 /*
index 37e16cd..5048266 100644 (file)
@@ -27,6 +27,7 @@
 #include "php_http_std_defs.h"
 #include "php_http_api.h"
 #include "php_http_headers_api.h"
+#include "php_http_info_api.h"
 
 #include <ctype.h>
 
@@ -244,26 +245,25 @@ PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, size_
 /* }}} */
 
 /* {{{ 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)
+PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, 
+       http_info_callback callback_func, void **callback_data TSRMLS_DC)
 {
-       const char *colon = NULL, *line = NULL, *begin = header, *crlfcrlf = NULL;
+       const char *colon = NULL, *line = NULL, *begin = header;
+       const char *body = http_locate_body(header);
        size_t header_len;
        zval array;
 
        Z_ARRVAL(array) = headers;
-
-       if (crlfcrlf = strstr(header, HTTP_CRLF HTTP_CRLF)) {
-               header_len = crlfcrlf - header + lenof(HTTP_CRLF);
-       } else {
-               header_len = strlen(header) + 1;
-       }
-
-
-       if (header_len < 2 || !strchr(header, ':')) {
+       header_len = body ? body - header : strlen(header) + 1;
+       
+/*
+       if (header_len < 2 || ((!lflf) && (!crlfcrlf) && (!strchr(header, ':')))) {
+               fprintf(stderr, "header_len: %lu, lflf: %p, crlfcrlf: %p, ':': %p\n(%s)\n",
+                       header_len, lflf, crlfcrlf, strchr(header, ':'), header);
                http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Cannot parse too short or malformed HTTP headers");
                return FAILURE;
        }
-
+*/
        line = header;
 
        while (header_len >= (size_t) (line - begin)) {
@@ -271,11 +271,26 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header
 
                switch (*line++)
                {
+                       case ':':
+                               if (!colon) {
+                                       colon = line - 1;
+                               }
+                       break;
+                       
                        case 0:
                                --value_len; /* we don't have CR so value length is one char less */
                        case '\n':
                                if ((!(*line - 1)) || ((*line != ' ') && (*line != '\t'))) {
+                                       http_info i;
+                                       
                                        /* response/request line */
+                                       if (SUCCESS == http_info_parse(header, &i)) {
+                                               callback_func(callback_data, &headers, &i TSRMLS_CC);
+                                               http_info_dtor(&i);
+                                               Z_ARRVAL(array) = headers;
+                                       } else
+                                       
+                                       /*
                     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) {
@@ -283,6 +298,7 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header
                                                        Z_ARRVAL(array) = headers;
                                                }
                                        } else
+                                       */
 
                                        /* "header: value" pair */
                                        if (colon) {
@@ -330,47 +346,12 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header
                                        header += line - header;
                                }
                        break;
-
-                       case ':':
-                               if (!colon) {
-                                       colon = line - 1;
-                               }
-                       break;
                }
        }
        return SUCCESS;
 }
 /* }}} */
 
-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."))) {
-               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"), "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", met, sep - http_line, 0);
-               add_assoc_stringl(&array, "Request Uri", url, strstr(sep, "HTTP/1.") - sep + 1 + 1, 0);
-       }
-}
-
 /* {{{ void http_get_request_headers_ex(HashTable *, zend_bool) */
 PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool prettify TSRMLS_DC)
 {
@@ -380,7 +361,7 @@ PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool pre
 
        Z_ARRVAL(array) = headers;
 
-       if (SUCCESS == zend_hash_find(&EG(symbol_table), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), (void **) &hsv)) {
+       if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &hsv)) {
                FOREACH_KEY(*hsv, key, idx) {
                        if (key && !strncmp(key, "HTTP_", 5)) {
                                zval **header;
diff --git a/http_info_api.c b/http_info_api.c
new file mode 100644 (file)
index 0000000..18fea6f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+   +----------------------------------------------------------------------+
+   | PECL :: http                                                         |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license, that  |
+   | is bundled with this package in the file LICENSE, and is available   |
+   | through the world-wide-web at http://www.php.net/license/3_0.txt.    |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2004-2005 Michael Wallner <mike@php.net>               |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#      include "config.h"
+#endif
+#include "php.h"
+
+#include "php_http.h"
+#include "php_http_api.h"
+#include "php_http_std_defs.h"
+#include "php_http_info_api.h"
+
+#include <ctype.h>
+
+ZEND_EXTERN_MODULE_GLOBALS(http);
+
+PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC)
+{
+       zval array;
+       Z_ARRVAL(array) = *headers;
+       
+       switch (info->type)
+       {
+               case IS_HTTP_REQUEST:
+                       add_assoc_string(&array, "Request Method", HTTP_INFO(info).request.method, 1);
+                       add_assoc_string(&array, "Request Uri", HTTP_INFO(info).request.URI, 1);
+               break;
+               
+               case IS_HTTP_RESPONSE:
+                       add_assoc_long(&array, "Response Code", (long) HTTP_INFO(info).response.code);
+                       add_assoc_string(&array, "Response Status", HTTP_INFO(info).response.status, 1);
+               break;
+       }
+}
+
+PHP_HTTP_API void _http_info_dtor(http_info *info)
+{
+       http_info_t *i = (http_info_t *) info;
+       
+       switch (info->type)
+       {
+               case IS_HTTP_REQUEST:
+                       STR_SET(i->request.method, NULL);
+                       STR_SET(i->request.URI, NULL);
+               break;
+               
+               case IS_HTTP_RESPONSE:
+                       STR_SET(i->response.status, NULL);
+               break;
+               
+               default:
+               break;
+       }
+}
+
+PHP_HTTP_API STATUS _http_info_parse_ex(const char *pre_header, http_info *info, zend_bool silent TSRMLS_DC)
+{
+       const char *end, *http;
+       
+       /* sane parameter */
+       if ((!pre_header) || (!*pre_header)) {
+               if (!silent) {
+                       http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Empty pre-header HTTP info");
+               }
+               return FAILURE;
+       }
+       
+       /* where's the end of the line */
+       if (!((end = strchr(pre_header, '\r')) || (end = strchr(pre_header, '\n')))) {
+               end = pre_header + strlen(pre_header);
+       }
+       
+       /* there must be HTTP/1.x in the line
+        * and nothing than SPACE or NUL after HTTP/1.x 
+        */
+       if (    (!(http = strstr(pre_header, "HTTP/1."))) || 
+                       (!(http < end)) ||
+                       (!isdigit(http[lenof("HTTP/1.")])) ||
+                       (http[lenof("HTTP/1.1")] && (!isspace(http[lenof("HTTP/1.1")])))) {
+               if (!silent) {
+                       http_error(HE_WARNING, HTTP_E_MALFORMED_HEADERS, "Invalid or missing HTTP/1.x protocol identification");
+               }
+               return FAILURE;
+       }
+
+#if 0
+       {
+               char *line = estrndup(pre_header, end - pre_header);
+               fprintf(stderr, "http_parse_info('%s')\n", line);
+               efree(line);
+       }
+#endif
+
+       info->http.version = atof(http + lenof("HTTP/"));
+       
+       /* is response */
+       if (pre_header == http) {
+               char *status = NULL;
+               const char *code = http + sizeof("HTTP/1.1");
+               
+               info->type = IS_HTTP_RESPONSE;
+               HTTP_INFO(info).response.code = (code && (end > code)) ? strtol(code, &status, 10) : 0;
+               HTTP_INFO(info).response.status = (status && (end > ++status)) ? estrndup(status, end - status) : ecalloc(1,1);
+               
+               return SUCCESS;
+       }
+       
+       /* is request */
+       else {
+               const char *url = strchr(pre_header, ' ');
+               
+               info->type = IS_HTTP_REQUEST;
+               if (url && http > url) {
+                       HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header);
+                       HTTP_INFO(info).request.URI = estrndup(url + 1, http - url - 2);
+               } else {
+                       HTTP_INFO(info).request.method = ecalloc(1,1);
+                       HTTP_INFO(info).request.URI = ecalloc(1,1);
+               }
+               
+               return SUCCESS;
+       }
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
index 8d062b1..42bae1a 100644 (file)
 
 ZEND_EXTERN_MODULE_GLOBALS(http);
 
-#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)
+#define http_message_info_callback _http_message_info_callback
+static void _http_message_info_callback(http_message **message, HashTable **headers, http_info *info TSRMLS_DC)
 {
-       size_t line_length;
-       char *crlf = NULL;
-       http_message *new, *old = (http_message *) *message;
-
-       if (crlf = strstr(http_line, HTTP_CRLF)) {
-               line_length = crlf - http_line;
-       } else {
-               line_length = strlen(http_line);
-       }
-
+       http_message *old = *message;
+       
+       /* advance message */
        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;
+               (*message) = http_message_new();
+               (*message)->parent = old;
+               (*headers) = &((*message)->hdrs);
        }
-
-       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"));
+       
+       (*message)->http.version = info->http.version;
+       
+       switch (info->type)
+       {
+               case IS_HTTP_REQUEST:
+                       (*message)->type = HTTP_MSG_REQUEST;
+                       HTTP_INFO(*message).request.URI = estrdup(HTTP_INFO(info).request.URI);
+                       HTTP_INFO(*message).request.method = estrdup(HTTP_INFO(info).request.method);
+               break;
+               
+               case IS_HTTP_RESPONSE:
+                       (*message)->type = HTTP_MSG_RESPONSE;
+                       HTTP_INFO(*message).response.code = HTTP_INFO(info).response.code;
+                       HTTP_INFO(*message).response.status = estrdup(HTTP_INFO(info).response.status);
+               break;
        }
 }
 
 #define http_message_init_type _http_message_init_type
 static inline void _http_message_init_type(http_message *message, http_message_type type)
 {
+       message->http.version = .0;
+       
        switch (message->type = type)
        {
                case HTTP_MSG_RESPONSE:
-                       message->info.response.http_version = .0;
-                       message->info.response.code = 0;
+                       message->http.info.response.code = 0;
+                       message->http.info.response.status = NULL;
                break;
 
                case HTTP_MSG_REQUEST:
-                       message->info.request.http_version = .0;
-                       message->info.request.method = NULL;
-                       message->info.request.URI = NULL;
+                       message->http.info.request.method = NULL;
+                       message->http.info.request.URI = NULL;
                break;
 
                case HTTP_MSG_NONE:
@@ -117,13 +107,19 @@ PHP_HTTP_API void _http_message_set_type(http_message *message, http_message_typ
        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);
-                       }
+               switch (message->type)
+               {
+                       case HTTP_MSG_REQUEST:
+                               STR_FREE(message->http.info.request.method);
+                               STR_FREE(message->http.info.request.URI);
+                       break;
+                       
+                       case HTTP_MSG_RESPONSE:
+                               STR_FREE(message->http.info.response.status);
+                       break;
+                       
+                       default:
+                       break;
                }
 
                /* init */
@@ -133,33 +129,28 @@ PHP_HTTP_API void _http_message_set_type(http_message *message, http_message_typ
 
 PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char *message, size_t message_length TSRMLS_DC)
 {
-       char *body = NULL;
+       char *body = NULL, *cr, *lf;
        zend_bool free_msg = msg ? 0 : 1;
 
-       if (message_length < HTTP_MSG_MIN_SIZE) {
-               return NULL;
-       }
-
-       if (!message) {
+       if ((!message) || (message_length < HTTP_MSG_MIN_SIZE)) {
                return NULL;
        }
 
        msg = http_message_init(msg);
 
-       if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, http_message_headers_cb, (void **) &msg)) {
+       if (SUCCESS != http_parse_headers_cb(message, &msg->hdrs, 1, (http_info_callback) http_message_info_callback, &msg)) {
                if (free_msg) {
-                       http_message_free(msg);
+                       http_message_free(&msg);
                }
                return NULL;
        }
 
-       /* header parsing stops at CRLF CRLF */
+       /* header parsing stops at (CR)LF (CR)LF */
        if (body = strstr(message, HTTP_CRLF HTTP_CRLF)) {
                zval *c;
                const char *continue_at = NULL;
 
                body += lenof(HTTP_CRLF HTTP_CRLF);
-
                /* message has content-length header */
                if (c = http_message_header(msg, "Content-Length")) {
                        long len = atol(Z_STRVAL_P(c));
@@ -242,15 +233,17 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_
        {
                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);
+                               msg->http.info.request.method,
+                               msg->http.info.request.URI,
+                               msg->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);
+                       phpstr_appendf(&str, "HTTP/%1.1f %d%s%s" HTTP_CRLF,
+                               msg->http.version,
+                               msg->http.info.response.code,
+                               *msg->http.info.response.status ? " ":"",
+                               msg->http.info.response.status);
                break;
 
                case HTTP_MSG_NONE:
@@ -315,6 +308,56 @@ PHP_HTTP_API void _http_message_serialize(http_message *message, char **string,
        phpstr_dtor(&str);
 }
 
+PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *obj TSRMLS_DC)
+{
+       zval strct;
+       zval *headers;
+       
+       Z_TYPE(strct) = IS_ARRAY;
+       Z_ARRVAL(strct) = HASH_OF(obj);
+       
+       add_assoc_long(&strct, "type", msg->type);
+       add_assoc_double(&strct, "httpVersion", msg->http.version);
+       switch (msg->type)
+       {
+               case HTTP_MSG_RESPONSE:
+                       add_assoc_long(&strct, "responseCode", msg->http.info.response.code);
+                       add_assoc_string(&strct, "responseStatus", msg->http.info.response.status, 1);
+               break;
+               
+               case HTTP_MSG_REQUEST:
+                       add_assoc_string(&strct, "requestMethod", msg->http.info.request.method, 1);
+                       add_assoc_string(&strct, "requestUri", msg->http.info.request.URI, 1);
+               break;
+       }
+       
+       MAKE_STD_ZVAL(headers);
+       array_init(headers);
+       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+       add_assoc_zval(&strct, "headers", headers);
+       zval_ptr_dtor(&headers);
+       
+       add_assoc_stringl(&strct, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg), 1);
+       
+       if (msg->parent) {
+               zval *parent;
+               
+               MAKE_STD_ZVAL(parent);
+               if (Z_TYPE_P(obj) == IS_ARRAY) {
+                       array_init(parent);
+               } else {
+                       object_init(parent);
+               }
+               add_assoc_zval(&strct, "parentMessage", parent);
+               http_message_tostruct_recursive(msg->parent, parent);
+               zval_ptr_dtor(&parent);
+       } else {
+               add_assoc_null(&strct, "parentMessage");
+       }
+       http_message_dtor(msg);
+       efree(msg);
+}
+
 PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
 {
        STATUS rs = FAILURE;
@@ -334,16 +377,16 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
                                                zval **data;
                                                
                                                FOREACH_VAL(*val, data) {
-                                                       http_send_header_ex(key, strlen(key), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first);
+                                                       http_send_header_ex(key, strlen(key), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first, NULL);
                                                        first = 0;
                                                }
                                        } else {
-                                               http_send_header_ex(key, strlen(key), Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1);
+                                               http_send_header_ex(key, strlen(key), Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1, NULL);
                                        }
                                        key = NULL;
                                }
                        }
-                       rs =    SUCCESS == http_send_status(message->info.response.code) &&
+                       rs =    SUCCESS == http_send_status(message->http.info.response.code) &&
                                        SUCCESS == http_send_data(PHPSTR_VAL(message), PHPSTR_LEN(message)) ?
                                        SUCCESS : FAILURE;
                }
@@ -374,26 +417,26 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
                                        host = estrndup(Z_STRVAL_PP(zhost), host_len = Z_STRLEN_PP(zhost));
                                }
                                uri = http_absolute_uri_ex(
-                                       message->info.request.URI, strlen(message->info.request.URI),
+                                       message->http.info.request.URI, strlen(message->http.info.request.URI),
                                        NULL, 0, host, host_len, port);
                                efree(host);
                        } else {
-                               uri = http_absolute_uri(message->info.request.URI);
+                               uri = http_absolute_uri(message->http.info.request.URI);
                        }
 
-                       if (!strcasecmp("POST", message->info.request.method)) {
+                       if (!strcasecmp("POST", message->http.info.request.method)) {
                                http_request_body body = {HTTP_REQUEST_BODY_CSTRING, PHPSTR_VAL(message), PHPSTR_LEN(message)};
                                rs = http_post(uri, &body, Z_ARRVAL(options), NULL, NULL);
                        } else
-                       if (!strcasecmp("GET", message->info.request.method)) {
+                       if (!strcasecmp("GET", message->http.info.request.method)) {
                                rs = http_get(uri, Z_ARRVAL(options), NULL, NULL);
                        } else
-                       if (!strcasecmp("HEAD", message->info.request.method)) {
+                       if (!strcasecmp("HEAD", message->http.info.request.method)) {
                                rs = http_head(uri, Z_ARRVAL(options), NULL, NULL);
                        } else {
                                http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD,
                                        "Cannot send HttpMessage. Request method %s not supported",
-                                       message->info.request.method);
+                                       message->http.info.request.method);
                        }
 
                        efree(uri);
@@ -432,28 +475,33 @@ PHP_HTTP_API void _http_message_dtor(http_message *message)
        if (message) {
                zend_hash_destroy(&message->hdrs);
                phpstr_dtor(PHPSTR(message));
-               if (HTTP_MSG_TYPE(REQUEST, message)) {
-                       if (message->info.request.method) {
-                               efree(message->info.request.method);
-                               message->info.request.method = NULL;
-                       }
-                       if (message->info.request.URI) {
-                               efree(message->info.request.URI);
-                               message->info.request.URI = NULL;
-                       }
+               
+               switch (message->type)
+               {
+                       case HTTP_MSG_REQUEST:
+                               STR_SET(message->http.info.request.method, NULL);
+                               STR_SET(message->http.info.request.URI, NULL);
+                       break;
+                       
+                       case HTTP_MSG_RESPONSE:
+                               STR_SET(message->http.info.response.status, NULL);
+                       break;
+                       
+                       default:
+                       break;
                }
        }
 }
 
-PHP_HTTP_API void _http_message_free(http_message *message)
+PHP_HTTP_API void _http_message_free(http_message **message)
 {
-       if (message) {
-               if (message->parent) {
-                       http_message_free(message->parent);
-                       message->parent = NULL;
+       if (*message) {
+               if ((*message)->parent) {
+                       http_message_free(&(*message)->parent);
                }
-               http_message_dtor(message);
-               efree(message);
+               http_message_dtor(*message);
+               efree(*message);
+               *message = NULL;
        }
 }
 
index 18d3793..108848b 100644 (file)
@@ -243,21 +243,7 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type
                break;
 
                case HTTP_MSG_PROPHASH_HTTP_VERSION:
-                       switch (msg->type)
-                       {
-                               case HTTP_MSG_REQUEST:
-                                       RETVAL_DOUBLE(msg->info.request.http_version);
-                               break;
-
-                               case HTTP_MSG_RESPONSE:
-                                       RETVAL_DOUBLE(msg->info.response.http_version);
-                               break;
-
-                               case HTTP_MSG_NONE:
-                               default:
-                                       RETVAL_NULL();
-                               break;
-                       }
+                       RETVAL_DOUBLE(msg->http.version);
                break;
 
                case HTTP_MSG_PROPHASH_BODY:
@@ -283,25 +269,22 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type
                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->parent;
-                               zend_objects_store_add_ref(return_value TSRMLS_CC);
                        } else {
                                RETVAL_NULL();
                        }
                break;
 
                case HTTP_MSG_PROPHASH_REQUEST_METHOD:
-                       if (HTTP_MSG_TYPE(REQUEST, msg) && msg->info.request.method) {
-                               RETVAL_STRING(msg->info.request.method, 1);
+                       if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.method) {
+                               RETVAL_STRING(msg->http.info.request.method, 1);
                        } else {
                                RETVAL_NULL();
                        }
                break;
 
                case HTTP_MSG_PROPHASH_REQUEST_URI:
-                       if (HTTP_MSG_TYPE(REQUEST, msg) && msg->info.request.URI) {
-                               RETVAL_STRING(msg->info.request.URI, 1);
+                       if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.URI) {
+                               RETVAL_STRING(msg->http.info.request.URI, 1);
                        } else {
                                RETVAL_NULL();
                        }
@@ -309,12 +292,20 @@ static zval *_http_message_object_read_prop(zval *object, zval *member, int type
 
                case HTTP_MSG_PROPHASH_RESPONSE_CODE:
                        if (HTTP_MSG_TYPE(RESPONSE, msg)) {
-                               RETVAL_LONG(msg->info.response.code);
+                               RETVAL_LONG(msg->http.info.response.code);
                        } else {
                                RETVAL_NULL();
                        }
                break;
-
+               
+               case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
+                       if (HTTP_MSG_TYPE(RESPONSE, msg) && msg->http.info.response.status) {
+                               RETVAL_STRING(msg->http.info.response.status, 1);
+                       } else {
+                               RETVAL_NULL();
+                       }
+               break;
+               
                default:
                        RETVAL_NULL();
                break;
@@ -339,36 +330,12 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va
        {
                case HTTP_MSG_PROPHASH_TYPE:
                        convert_to_long_ex(&value);
-                       if ((http_message_type) Z_LVAL_P(value) != msg->type) {
-                               if (HTTP_MSG_TYPE(REQUEST, msg)) {
-                                       if (msg->info.request.method) {
-                                               efree(msg->info.request.method);
-                                       }
-                                       if (msg->info.request.URI) {
-                                               efree(msg->info.request.URI);
-                                       }
-                               }
-                               msg->type = Z_LVAL_P(value);
-                               if (HTTP_MSG_TYPE(REQUEST, msg)) {
-                                       msg->info.request.method = NULL;
-                                       msg->info.request.URI = NULL;
-                               }
-                       }
-
+                       http_message_set_type(msg, Z_LVAL_P(value));
                break;
 
                case HTTP_MSG_PROPHASH_HTTP_VERSION:
                        convert_to_double_ex(&value);
-                       switch (msg->type)
-                       {
-                               case HTTP_MSG_REQUEST:
-                                       msg->info.request.http_version = Z_DVAL_P(value);
-                               break;
-
-                               case HTTP_MSG_RESPONSE:
-                                       msg->info.response.http_version = Z_DVAL_P(value);
-                               break;
-                       }
+                       msg->http.version = Z_DVAL_P(value);
                break;
 
                case HTTP_MSG_PROPHASH_BODY:
@@ -394,31 +361,32 @@ static void _http_message_object_write_prop(zval *object, zval *member, zval *va
                break;
 
                case HTTP_MSG_PROPHASH_REQUEST_METHOD:
-                       convert_to_string_ex(&value);
                        if (HTTP_MSG_TYPE(REQUEST, msg)) {
-                               if (msg->info.request.method) {
-                                       efree(msg->info.request.method);
-                               }
-                               msg->info.request.method = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
+                               convert_to_string_ex(&value);
+                               STR_SET(msg->http.info.request.method, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
                        }
                break;
 
                case HTTP_MSG_PROPHASH_REQUEST_URI:
-                       convert_to_string_ex(&value);
                        if (HTTP_MSG_TYPE(REQUEST, msg)) {
-                               if (msg->info.request.URI) {
-                                       efree(msg->info.request.URI);
-                               }
-                               msg->info.request.URI = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
+                               convert_to_string_ex(&value);
+                               STR_SET(msg->http.info.request.URI, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
                        }
                break;
 
                case HTTP_MSG_PROPHASH_RESPONSE_CODE:
-                       convert_to_long_ex(&value);
                        if (HTTP_MSG_TYPE(RESPONSE, msg)) {
-                               msg->info.response.code = Z_LVAL_P(value);
+                               convert_to_long_ex(&value);
+                               msg->http.info.response.code = Z_LVAL_P(value);
                        }
                break;
+               
+               case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
+                       if (HTTP_MSG_TYPE(RESPONSE, msg)) {
+                               convert_to_string_ex(&value);
+                               STR_SET(msg->http.info.response.status, estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)));
+                       }
+                       
        }
 }
 
@@ -451,39 +419,39 @@ static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC)
        zend_hash_clean(OBJ_PROP(obj));
 
        ASSOC_PROP(obj, long, "type", msg->type);
-       ASSOC_STRINGL(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
-
-       MAKE_STD_ZVAL(headers);
-       array_init(headers);
-
-       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
-       ASSOC_PROP(obj, zval, "headers", headers);
+       ASSOC_PROP(obj, double, "httpVersion", msg->http.version);
 
        switch (msg->type)
        {
                case HTTP_MSG_REQUEST:
-                       ASSOC_PROP(obj, double, "httpVersion", msg->info.request.http_version);
                        ASSOC_PROP(obj, long, "responseCode", 0);
-                       ASSOC_STRING(obj, "requestMethod", msg->info.request.method);
-                       ASSOC_STRING(obj, "requestUri", msg->info.request.URI);
+                       ASSOC_STRINGL(obj, "responseStatus", "", 0);
+                       ASSOC_STRING(obj, "requestMethod", msg->http.info.request.method);
+                       ASSOC_STRING(obj, "requestUri", msg->http.info.request.URI);
                break;
 
                case HTTP_MSG_RESPONSE:
-                       ASSOC_PROP(obj, double, "httpVersion", msg->info.response.http_version);
-                       ASSOC_PROP(obj, long, "responseCode", msg->info.response.code);
-                       ASSOC_STRING(obj, "requestMethod", "");
-                       ASSOC_STRING(obj, "requestUri", "");
+                       ASSOC_PROP(obj, long, "responseCode", msg->http.info.response.code);
+                       ASSOC_STRING(obj, "responseStatus", msg->http.info.response.status);
+                       ASSOC_STRINGL(obj, "requestMethod", "", 0);
+                       ASSOC_STRINGL(obj, "requestUri", "", 0);
                break;
 
                case HTTP_MSG_NONE:
                default:
-                       ASSOC_PROP(obj, double, "httpVersion", 0.0);
                        ASSOC_PROP(obj, long, "responseCode", 0);
-                       ASSOC_STRING(obj, "requestMethod", "");
-                       ASSOC_STRING(obj, "requestUri", "");
+                       ASSOC_STRINGL(obj, "responseStatus", "", 0);
+                       ASSOC_STRINGL(obj, "requestMethod", "", 0);
+                       ASSOC_STRINGL(obj, "requestUri", "", 0);
                break;
        }
 
+       MAKE_STD_ZVAL(headers);
+       array_init(headers);
+       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+       ASSOC_PROP(obj, zval, "headers", headers);
+       ASSOC_STRINGL(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
+
        return OBJ_PROP(obj);
 }
 
@@ -659,7 +627,7 @@ PHP_METHOD(HttpMessage, getResponseCode)
                        RETURN_NULL();
                }
 
-               RETURN_LONG(obj->message->info.response.code);
+               RETURN_LONG(obj->message->http.info.response.code);
        }
 }
 /* }}} */
@@ -688,7 +656,7 @@ PHP_METHOD(HttpMessage, setResponseCode)
                RETURN_FALSE;
        }
 
-       obj->message->info.response.code = code;
+       obj->message->http.info.response.code = code;
        RETURN_TRUE;
 }
 /* }}} */
@@ -710,7 +678,7 @@ PHP_METHOD(HttpMessage, getRequestMethod)
                        RETURN_NULL();
                }
 
-               RETURN_STRING(obj->message->info.request.method, 1);
+               RETURN_STRING(obj->message->http.info.request.method, 1);
        }
 }
 /* }}} */
@@ -743,7 +711,7 @@ PHP_METHOD(HttpMessage, setRequestMethod)
                RETURN_FALSE;
        }
 
-       STR_SET(obj->message->info.request.method, estrndup(method, method_len));
+       STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
        RETURN_TRUE;
 }
 /* }}} */
@@ -764,7 +732,7 @@ PHP_METHOD(HttpMessage, getRequestUri)
                        RETURN_NULL();
                }
 
-               RETURN_STRING(obj->message->info.request.URI, 1);
+               RETURN_STRING(obj->message->http.info.request.URI, 1);
        }
 }
 /* }}} */
@@ -793,7 +761,7 @@ PHP_METHOD(HttpMessage, setRequestUri)
                RETURN_FALSE;
        }
 
-       STR_SET(obj->message->info.request.URI, estrndup(URI, URIlen));
+       STR_SET(obj->message->http.info.request.URI, estrndup(URI, URIlen));
        RETURN_TRUE;
 }
 /* }}} */
@@ -811,21 +779,7 @@ PHP_METHOD(HttpMessage, getHttpVersion)
                double version;
                getObject(http_message_object, obj);
 
-               switch (obj->message->type)
-               {
-                       case HTTP_MSG_RESPONSE:
-                               version = obj->message->info.response.http_version;
-                       break;
-
-                       case HTTP_MSG_REQUEST:
-                               version = obj->message->info.request.http_version;
-                       break;
-
-                       case HTTP_MSG_NONE:
-                       default:
-                               RETURN_NULL();
-               }
-               sprintf(ver, "%1.1lf", version);
+               sprintf(ver, "%1.1lf", obj->message->http.version);
                RETURN_STRINGL(ver, 3, 1);
        }
 }
@@ -846,11 +800,6 @@ PHP_METHOD(HttpMessage, setHttpVersion)
                return;
        }
 
-       if (HTTP_MSG_TYPE(NONE, obj->message)) {
-               http_error(HE_WARNING, HTTP_E_MESSAGE_TYPE, "Message is neither of type HTTP_MSG_RESPONSE nor HTTP_MSG_REQUEST");
-               RETURN_FALSE;
-       }
-
        convert_to_double(zv);
        sprintf(v, "%1.1lf", Z_DVAL_P(zv));
        if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
@@ -858,11 +807,7 @@ PHP_METHOD(HttpMessage, setHttpVersion)
                RETURN_FALSE;
        }
 
-       if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
-               obj->message->info.response.http_version = Z_DVAL_P(zv);
-       } else {
-               obj->message->info.request.http_version = Z_DVAL_P(zv);
-       }
+       obj->message->http.version = Z_DVAL_P(zv);
        RETURN_TRUE;
 }
 /* }}} */
index 5bb5b65..097049f 100644 (file)
@@ -464,7 +464,7 @@ PHP_HTTP_API STATUS _http_request_init(CURL *ch, http_request_method meth, char
                        phpstr_fix(qstr);
                        HTTP_CURL_OPT(COOKIE, http_request_data_copy(COPY_STRING, qstr->data));
                }
-               phpstr_free(qstr);
+               phpstr_free(&qstr);
        } else {
                HTTP_CURL_OPT(COOKIE, NULL);
        }
index d6447ca..f2e6c46 100644 (file)
@@ -525,11 +525,11 @@ STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this
 
                        } while ((response = response->parent) && (request = request->parent));
 
-                       http_message_free(free_msg);
+                       http_message_free(&free_msg);
                        phpstr_fix(&obj->history);
                }
 
-               UPD_PROP(obj, long, responseCode, msg->info.response.code);
+               UPD_PROP(obj, long, responseCode, msg->http.info.response.code);
 
                MAKE_STD_ZVAL(headers)
                array_init(headers);
index d21225a..0fb1248 100644 (file)
@@ -811,11 +811,11 @@ PHP_METHOD(HttpResponse, send)
                                        zval **data;
 
                                        FOREACH_VAL(*value, data) {
-                                               http_send_header_ex(name, strlen(name), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first);
+                                               http_send_header_ex(name, strlen(name), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first, NULL);
                                                first = 0;
                                        }
                                } else {
-                                       http_send_header_ex(name, strlen(name), Z_STRVAL_PP(value), Z_STRLEN_PP(value), 1);
+                                       http_send_header_ex(name, strlen(name), Z_STRVAL_PP(value), Z_STRLEN_PP(value), 1, NULL);
                                }
                                name = NULL;
                        }
@@ -862,7 +862,7 @@ PHP_METHOD(HttpResponse, send)
        {
                zval *cd = GET_STATIC_PROP(contentDisposition);
                if (Z_STRLEN_P(cd)) {
-                       http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1);
+                       http_send_header_ex("Content-Disposition", lenof("Content-Disposition"), Z_STRVAL_P(cd), Z_STRLEN_P(cd), 1, NULL);
                }
        }
 
index 9f11052..ba6122b 100644 (file)
@@ -149,10 +149,10 @@ static STATUS _http_send_chunk(const void *data, size_t begin, size_t end, http_
 /* }}} */
 
 /* {{{ STATUS http_send_header(char *, char *, zend_bool) */
-PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC)
 {
        STATUS ret;
-       size_t header_len = sizeof(": ") + name_len + value_len;
+       size_t header_len = sizeof(": ") + name_len + value_len + 1;
        char *header = emalloc(header_len + 1);
 
        header[header_len] = '\0';
@@ -176,7 +176,7 @@ PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header,
 /* }}} */
 
 /* {{{ STATUS http_send_last_modified(int) */
-PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC)
 {
        STATUS ret;
        char *date = http_date(t);
@@ -185,7 +185,7 @@ PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC)
                return FAILURE;
        }
 
-       ret = http_send_header("Last-Modified", date, 1);
+       ret = http_send_header_ex("Last-Modified", lenof("Last-Modifed"), date, strlen(date), 1, sent_header);
        efree(date);
 
        /* remember */
@@ -196,7 +196,7 @@ PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC)
 /* }}} */
 
 /* {{{ STATUS http_send_etag(char *, size_t) */
-PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC)
 {
        STATUS status;
        char *etag_header;
@@ -213,7 +213,13 @@ PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC)
        etag_header = ecalloc(1, sizeof("ETag: \"\"") + etag_len);
        sprintf(etag_header, "ETag: \"%s\"", etag);
        status = http_send_header_string(etag_header);
-       efree(etag_header);
+       
+       if (sent_header) {
+               *sent_header = etag_header;
+       } else {
+               efree(etag_header);
+       }
+       
        return status;
 }
 /* }}} */
@@ -230,7 +236,7 @@ PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_
        STR_FREE(HTTP_G(send).content_type);
        HTTP_G(send).content_type = estrndup(content_type, ct_len);
 
-       return http_send_header_ex("Content-Type", lenof("Content-Type"), content_type, ct_len, 1);
+       return http_send_header_ex("Content-Type", lenof("Content-Type"), content_type, ct_len, 1, NULL);
 }
 /* }}} */
 
@@ -381,9 +387,13 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send
                if (!(etag = http_etag(data_ptr, data_size, data_mode))) {
                        http_error(HE_NOTICE, HTTP_E_RUNTIME, "Failed to generate ETag for data source");
                } else {
-                       http_send_etag(etag, 32);
+                       char *sent_header = NULL;
+                       
+                       http_send_etag_ex(etag, 32, &sent_header);
                        if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
-                               return http_cache_exit_ex(etag, 1, 1);
+                               return http_exit_ex(304, sent_header, NULL, 0);
+                       } else {
+                               STR_FREE(sent_header);
                        }
                        efree(etag);
                }
@@ -391,7 +401,9 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send
 
        /* send 304 Not Modified if last modified matches */
        if (http_match_last_modified("HTTP_IF_MODIFIED_SINCE", HTTP_G(send).last_modified)) {
-               return http_cache_exit_ex(http_date(HTTP_G(send).last_modified), 0, 1);
+               char *sent_header = NULL;
+               http_send_last_modified_ex(HTTP_G(send).last_modified, &sent_header);
+               return http_exit_ex(304, sent_header, NULL, 0);
        }
 
        /* emit a content-length header */
index e66781f..10a9095 100644 (file)
@@ -197,12 +197,12 @@ PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_
        }
 
        if (SUCCESS != http_urlencode_hash_implementation(hash, qstr, arg_sep)) {
-               phpstr_free(qstr);
+               phpstr_free(&qstr);
                return FAILURE;
        }
 
        phpstr_data(qstr, encoded_data, encoded_len);
-       phpstr_free(qstr);
+       phpstr_free(&qstr);
 
        return SUCCESS;
 }
index d4c544d..5f4d438 100644 (file)
@@ -73,8 +73,8 @@ HTTP_BEGIN_ARGS(chunkedDecode, 1)
        HTTP_ARG_VAL(encoded_string, 0)
 HTTP_END_ARGS;
 
-HTTP_BEGIN_ARGS(splitResponse, 1)
-       HTTP_ARG_VAL(response_string, 0)
+HTTP_BEGIN_ARGS(parseMessage, 1)
+       HTTP_ARG_VAL(message_string, 0)
 HTTP_END_ARGS;
 
 HTTP_BEGIN_ARGS(parseHeaders, 1)
@@ -102,7 +102,7 @@ zend_function_entry http_util_object_fe[] = {
        HTTP_UTIL_ALIAS(matchEtag, http_match_etag)
        HTTP_UTIL_ALIAS(matchRequestHeader, http_match_request_header)
        HTTP_UTIL_ALIAS(chunkedDecode, http_chunked_decode)
-       HTTP_UTIL_ALIAS(splitResponse, http_split_response)
+       HTTP_UTIL_ALIAS(parseMessage, http_parse_message)
        HTTP_UTIL_ALIAS(parseHeaders, http_parse_headers)
        HTTP_UTIL_ALIAS(authBasic, http_auth_basic)
        HTTP_UTIL_ALIAS(authBasicCallback, http_auth_basic_cb)
index 81d5183..dcf4709 100644 (file)
--- a/missing.c
+++ b/missing.c
@@ -151,126 +151,6 @@ int zend_update_static_property(zend_class_entry *scope, char *name, size_t name
        return retval;
 }
 
-int trash(zend_class_entry *scope, char *name, size_t name_len, zval *value TSRMLS_DC)
-{
-       int retval;
-       zval **property = NULL;
-       zend_class_entry *old_scope = EG(scope);
-       
-       EG(scope) = scope;
-       
-       if (!(property = zend_std_get_static_property(scope, name, name_len, 0 TSRMLS_CC))) {
-               retval = FAILURE;
-       } else if (*property == value) {
-               retval = SUCCESS;
-       } else if (scope->type & ZEND_INTERNAL_CLASS) {
-               int refcount;
-               zend_uchar is_ref;
-       
-               refcount = (*property)->refcount;
-               is_ref = (*property)->is_ref;
-               
-               /* clean */
-               switch (Z_TYPE_PP(property))
-               {
-                       case IS_BOOL: case IS_LONG: case IS_NULL:
-                       break;
-                       
-                       case IS_RESOURCE:
-                               zend_list_delete(Z_LVAL_PP(property));
-                       break;
-                       
-                       case IS_STRING: case IS_CONSTANT:
-                               free(Z_STRVAL_PP(property));
-                       break;
-                       
-                       case IS_OBJECT:
-                               if (Z_OBJ_HT_PP(property)->del_ref) {
-                                       Z_OBJ_HT_PP(property)->del_ref(*property TSRMLS_CC);
-                               }
-                       break;
-                       
-                       case IS_ARRAY: case IS_CONSTANT_ARRAY:
-                               if (Z_ARRVAL_PP(property) && Z_ARRVAL_PP(property) != &EG(symbol_table)) {
-                                       zend_hash_destroy(Z_ARRVAL_PP(property));
-                                       free(Z_ARRVAL_PP(property));
-                               }
-                       break;
-               }
-               
-               /* copy */
-               **property = *value;
-               
-               /* ctor */              
-               switch (Z_TYPE_PP(property))
-               {
-                       case IS_BOOL: case IS_LONG: case IS_NULL:
-                       break;
-                       
-                       case IS_RESOURCE:
-                               zend_list_addref(Z_LVAL_PP(property));
-                       break;
-                       
-                       case IS_STRING: case IS_CONSTANT:
-                               Z_STRVAL_PP(property) = (char *) zend_strndup(Z_STRVAL_PP(property), Z_STRLEN_PP(property));
-                       break;
-                       
-                       case IS_OBJECT:
-                               if (Z_OBJ_HT_PP(property)->add_ref) {
-                                       Z_OBJ_HT_PP(property)->add_ref(*property TSRMLS_CC);
-                               }
-                       break;
-                       
-                       case IS_ARRAY: case IS_CONSTANT_ARRAY:
-                       {
-                               if (Z_ARRVAL_PP(property) != &EG(symbol_table)) {
-                                       zval *tmp;
-                                       HashTable *old = Z_ARRVAL_PP(property);
-                                       
-                                       Z_ARRVAL_PP(property) = (HashTable *) malloc(sizeof(HashTable));
-                                       zend_hash_init(Z_ARRVAL_PP(property), 0, NULL, ZVAL_PTR_DTOR, 0);
-                                       zend_hash_copy(Z_ARRVAL_PP(property), old, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
-                               }
-                       }
-                       break;
-               }
-               
-               (*property)->refcount = refcount;
-               (*property)->is_ref = is_ref;
-               
-               retval = SUCCESS;
-               
-       } else {
-               if (PZVAL_IS_REF(*property)) {
-                       zval_dtor(*property);
-                       (*property)->type = value->type;
-                       (*property)->value = value->value;
-                       
-                       if (value->refcount) {
-                               zval_copy_ctor(*property);
-                       }
-                       
-                       retval = SUCCESS;
-               } else {
-                       value->refcount++;
-                       if (PZVAL_IS_REF(value)) {
-                               SEPARATE_ZVAL(&value);
-                       }
-                       
-                       retval = zend_hash_update(scope->static_members, name, name_len, &value, sizeof(zval *), NULL);
-               }
-       }
-       
-       if (!value->refcount) {
-               zval_dtor(value);
-               FREE_ZVAL(value);
-       }
-       
-       EG(scope) = old_scope;
-       
-       return retval;
-}
-
 int zend_update_static_property_bool(zend_class_entry *scope, char *name, size_t name_len, zend_bool value TSRMLS_DC)
 {
        zval *tmp = tmp_zval();
index 1b0f213..4dffa67 100644 (file)
@@ -46,7 +46,11 @@ ZEND_BEGIN_MODULE_GLOBALS(http)
        } etag;
 
        struct _http_globals_log {
+               char *auth;
                char *cache;
+               char *redirect;
+               char *allowed_methods;
+               char *composite;
        } log;
 
        struct _http_globals_send {
@@ -64,7 +68,7 @@ ZEND_BEGIN_MODULE_GLOBALS(http)
                } methods;
 
 #ifdef HTTP_HAVE_CURL
-               struct _http_globlas_request_copies {
+               struct _http_globals_request_copies {
                        zend_llist strings;
                        zend_llist slists;
                        zend_llist contexts;
@@ -107,7 +111,6 @@ PHP_FUNCTION(http_send_data);
 PHP_FUNCTION(http_send_file);
 PHP_FUNCTION(http_send_stream);
 PHP_FUNCTION(http_chunked_decode);
-PHP_FUNCTION(http_split_response);
 PHP_FUNCTION(http_parse_message);
 PHP_FUNCTION(http_parse_headers);
 PHP_FUNCTION(http_get_request_headers);
index 472c4b9..8906e2c 100644 (file)
@@ -35,9 +35,9 @@ extern STATUS _http_parse_key_list(const char *list, HashTable *items, char sepa
 #define http_error_ex _http_error_ex
 extern void _http_error_ex(long type, long code, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
 
-#define http_exit(s, h) http_exit_ex((s), (h), 1)
-#define http_exit_ex(s, h, f) _http_exit_ex((s), (h), (f) TSRMLS_CC)
-extern STATUS _http_exit_ex(int status, char *header, zend_bool free_header TSRMLS_DC);
+#define http_exit(s, h) http_exit_ex((s), (h), NULL, 1)
+#define http_exit_ex(s, h, b, e) _http_exit_ex((s), (h), (b), (e) TSRMLS_CC)
+extern STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC);
 
 #define http_check_method(m) http_check_method_ex((m), HTTP_KNOWN_METHODS)
 #define http_check_method_ex(m, a) _http_check_method_ex((m), (a))
@@ -60,8 +60,20 @@ PHP_HTTP_API STATUS _http_get_request_body_ex(char **body, size_t *length, zend_
 #define http_chunked_decode(e, el, d, dl) _http_chunked_decode((e), (el), (d), (dl) TSRMLS_CC)
 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, rl, h, b, bl) _http_split_response((r), (rl), (h), (b), (bl) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_split_response(char *response, size_t repsonse_len, HashTable *headers, char **body, size_t *body_len TSRMLS_DC);
+#define http_locate_body _http_locate_body
+static inline const char *_http_locate_body(const char *message)
+{
+       const char *cr = strstr(message, "\r\n\r\n");
+       const char *lf = strstr(message, "\n\n");
+
+       if (lf && cr) {
+               return MIN(lf + 2, cr + 4);
+       } else if (lf || cr) {
+               return MAX(lf + 2, cr + 4);
+       } else {
+               return NULL;
+       }
+}
 
 #endif
 
index e5b618f..e420963 100644 (file)
 #include "php_http_api.h"
 #include "php_http_send_api.h"
 
-#define http_cache_exit(t, e) http_cache_exit_ex((t), (e), 1)
-#define http_cache_exit_ex(t, e, f) _http_cache_exit_ex((t), (e), (f) TSRMLS_CC)
-extern STATUS _http_cache_exit_ex(char *cache_token, zend_bool etag, zend_bool free_token TSRMLS_DC);
-
 #define http_etag(p, l, m) _http_etag((p), (l), (m) TSRMLS_CC)
 PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC);
 
index d3221f5..b02e4c8 100644 (file)
@@ -19,6 +19,7 @@
 #define PHP_HTTP_HEADERS_API_H
 
 #include "php_http_std_defs.h"
+#include "php_http_info_api.h"
 
 typedef enum {
        RANGE_OK,
@@ -26,15 +27,10 @@ typedef enum {
        RANGE_ERR
 } http_range_status;
 
-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(const char *http_line, HashTable **headers, void **cb_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(h, a) _http_parse_headers_ex((h), Z_ARRVAL_P(a), 1, http_info_default_callback, NULL TSRMLS_CC)
+#define http_parse_headers_ex(h, ht, p) _http_parse_headers_ex((h), (ht), (p), http_info_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);
+PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *headers, zend_bool prettify, http_info_callback callback_func, void **callback_data TSRMLS_DC);
 
 #define http_get_request_headers(h) _http_get_request_headers_ex(Z_ARRVAL_P(h), 1 TSRMLS_CC)
 #define http_get_request_headers_ex(h, p) _http_get_request_headers_ex((h), (p) TSRMLS_CC)
diff --git a/php_http_info_api.h b/php_http_info_api.h
new file mode 100644 (file)
index 0000000..cd229ed
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+   +----------------------------------------------------------------------+
+   | PECL :: http                                                         |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license, that  |
+   | is bundled with this package in the file LICENSE, and is available   |
+   | through the world-wide-web at http://www.php.net/license/3_0.txt.    |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2004-2005 Michael Wallner <mike@php.net>               |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_HTTP_INFO_API_H
+#define PHP_HTTP_INFO_API_H
+
+#define IS_HTTP_REQUEST                1
+#define IS_HTTP_RESPONSE       2
+
+#define HTTP_INFO(ptr) (ptr)->http.info
+
+typedef struct {
+       char *method;
+       char *URI;
+} http_request_info;
+
+typedef struct {
+       int code;
+       char *status;
+} http_response_info;
+
+typedef union {
+       http_request_info request;
+       http_response_info response;
+} http_info_t;
+
+struct http_info {
+       http_info_t info;
+       double version;
+};
+
+typedef struct {
+       struct http_info http;
+       int type;
+} http_info;
+
+typedef void (*http_info_callback)(void **callback_data, HashTable **headers, http_info *info TSRMLS_DC);
+
+#define http_info_default_callback _http_info_default_callback
+PHP_HTTP_API void _http_info_default_callback(void **nothing, HashTable **headers, http_info *info TSRMLS_DC);
+#define http_info_dtor _http_info_dtor
+PHP_HTTP_API void _http_info_dtor(http_info *info);
+#define http_info_parse(p, i) _http_info_parse_ex((p), (i), 1 TSRMLS_CC)
+#define http_info_parse_ex(p, i, s) _http_info_parse_ex((p), (i), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http__infoparse_ex(const char *pre_header, http_info *info , zend_bool silent TSRMLS_DC);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
+
index 16f4fc2..9ba6081 100644 (file)
 #ifndef PHP_HTTP_MESSAGE_API_H
 #define PHP_HTTP_MESSAGE_API_H
 
+#include "php_http_info_api.h"
 #include "phpstr/phpstr.h"
 
 typedef enum {
-       HTTP_MSG_NONE,
-       HTTP_MSG_REQUEST,
-       HTTP_MSG_RESPONSE
+       HTTP_MSG_NONE           = 0,
+       HTTP_MSG_REQUEST        = IS_HTTP_REQUEST,
+       HTTP_MSG_RESPONSE       = IS_HTTP_RESPONSE,
 } http_message_type;
 
 typedef struct _http_message http_message;
@@ -32,26 +33,12 @@ struct _http_message {
        phpstr body;
        HashTable hdrs;
        http_message_type type;
-
-       union {
-               struct {
-                       double http_version;
-                       char *method;
-                       char *URI;
-               } request;
-
-               struct {
-                       double http_version;
-                       int code;
-               } response;
-
-       } info;
-
+       struct http_info http;
        http_message *parent;
 };
 
-/* required minimum length of an HTTP message "HTTP/1.1 200\r\n" */
-#define HTTP_MSG_MIN_SIZE 15
+/* required minimum length of an HTTP message "HTTP/1.1" */
+#define HTTP_MSG_MIN_SIZE 8
 
 /* shorthand for type checks */
 #define HTTP_MSG_TYPE(TYPE, msg) ((msg) && ((msg)->type == HTTP_MSG_ ##TYPE))
@@ -85,6 +72,9 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_
 #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_tostruct_recursive(m, s) _http_message_tostruct_recursive((m), (s) TSRMLS_CC)
+PHP_HTTP_API void _http_message_tostruct_recursive(http_message *msg, zval *strct TSRMLS_DC);
+
 #define http_message_send(m) _http_message_send((m) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC);
 
@@ -95,7 +85,7 @@ PHP_HTTP_API http_message *_http_message_dup(http_message *msg TSRMLS_DC);
 PHP_HTTP_API void _http_message_dtor(http_message *message);
 
 #define http_message_free(m) _http_message_free((m))
-PHP_HTTP_API void _http_message_free(http_message *message);
+PHP_HTTP_API void _http_message_free(http_message **message);
 
 #endif
 
index 5b9e016..84a0858 100644 (file)
@@ -29,21 +29,23 @@ typedef enum {
 
 #define http_send_status(s) sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (s) TSRMLS_CC)
 #define http_send_header(n, v, r) _http_send_header_ex((n), strlen(n), (v), strlen(v), (r) TSRMLS_CC)
-#define http_send_header_ex(n, nl, v, vl, r) _http_send_header_ex((n), (nl), (v), (vl), (r) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace TSRMLS_DC);
+#define http_send_header_ex(n, nl, v, vl, r, s) _http_send_header_ex((n), (nl), (v), (vl), (r), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC);
 #define http_send_header_string(h) _http_send_status_header_ex(0, (h), 1 TSRMLS_CC)
 #define http_send_header_string_ex(h, r) _http_send_status_header_ex(0, (h), (r) TSRMLS_CC)
 #define http_send_status_header(s, h) _http_send_status_header_ex((s), (h), 1 TSRMLS_CC)
 #define http_send_status_header_ex(s, h, r) _http_send_status_header_ex((s), (h), (r) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_send_status_header_ex(int status, const char *header, zend_bool replace TSRMLS_DC);
 
-#define http_send_last_modified(t) _http_send_last_modified((t) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_last_modified(time_t t TSRMLS_DC);
+#define http_send_last_modified(t) _http_send_last_modified_ex((t), NULL TSRMLS_CC)
+#define http_send_last_modified_ex(t, s) _http_send_last_modified_ex((t), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_last_modified_ex(time_t t, char **sent_header TSRMLS_DC);
 
-#define http_send_etag(e, l) _http_send_etag((e), (l) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_etag(const char *etag, size_t etag_len TSRMLS_DC);
+#define http_send_etag(e, l) _http_send_etag_ex((e), (l), NULL TSRMLS_CC)
+#define http_send_etag_ex(e, l, s) _http_send_etag_ex((e), (l), (s) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_etag_ex(const char *etag, size_t etag_len, char **sent_header TSRMLS_DC);
 
-#define http_send_cache_control(cc, cl) http_send_header_ex("Cache-Control", lenof("Cache-Control"), (cc), (cl), 1)
+#define http_send_cache_control(cc, cl) http_send_header_ex("Cache-Control", lenof("Cache-Control"), (cc), (cl), 1, NULL)
 
 #define http_send_content_type(c, l) _http_send_content_type((c), (l) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_send_content_type(const char *content_type, size_t ct_len TSRMLS_DC);
index e115b56..8bef4f8 100644 (file)
@@ -36,10 +36,21 @@ typedef int STATUS;
 /* lenof() */
 #define lenof(S) (sizeof(S) - 1)
 
+#ifndef MIN
+#      define MIN(a,b) (a<b?a:b)
+#endif
+#ifndef MAX
+#      define MAX(a,b) (a>b?a:b)
+#endif
+
 /* STR_SET() */
-#define STR_SET(target, source) \
-       if(target) efree(target); \
-       target = source
+#ifndef STR_SET
+#      define STR_SET(STR, SET) \
+       { \
+               STR_FREE(STR); \
+               STR = SET; \
+       }
+#endif
 
 /* return bool (v == SUCCESS) */
 #define RETVAL_SUCCESS(v) RETVAL_BOOL(SUCCESS == (v))
index 0742ef8..7357287 100644 (file)
@@ -32,8 +32,8 @@ PHP_METHOD(HttpUtil, negotiateCharset);
 PHP_METHOD(HttpUtil, matchModified);
 PHP_METHOD(HttpUtil, matchEtag);
 PHP_METHOD(HttpUtil, chunkedDecode);
-PHP_METHOD(HttpUtil, splitResponse);
 PHP_METHOD(HttpUtil, parseHeaders);
+PHP_METHOD(HttpUril, parseMessage);
 PHP_METHOD(HttpUtil, authBasic);
 PHP_METHOD(HttpUtil, authBasicCallback);
 
index 8d8df3e..acee06f 100644 (file)
@@ -235,19 +235,17 @@ PHPSTR_API int phpstr_cmp(phpstr *left, phpstr *right)
 
 PHPSTR_API void phpstr_dtor(phpstr *buf)
 {
-       if (buf->data) {
-               efree(buf->data);
-               buf->data = NULL;
-       }
+       STR_SET(buf->data, NULL);
        buf->used = 0;
        buf->free = 0;
 }
 
-PHPSTR_API void phpstr_free(phpstr *buf)
+PHPSTR_API void phpstr_free(phpstr **buf)
 {
-       if (buf) {
-               phpstr_dtor(buf);
-               efree(buf);
+       if (*buf) {
+               phpstr_dtor(*buf);
+               efree(*buf);
+               *buf = NULL;
        }
 }
 
index 40c59ed..a36f88a 100644 (file)
@@ -6,6 +6,14 @@
 
 #include "php.h"
 
+#ifndef STR_SET
+#      define STR_SET(STR, SET) \
+       { \
+               STR_FREE(STR); \
+               STR = SET; \
+       }
+#endif
+
 #if defined(PHP_WIN32)
 #      if defined(PHPSTR_EXPORTS)
 #              define PHPSTR_API __declspec(dllexport)
 
 #define FREE_PHPSTR_PTR(STR) efree(STR)
 #define FREE_PHPSTR_VAL(STR) phpstr_dtor(STR)
-#define FREE_PHPSTR_ALL(STR) phpstr_free(STR)
+#define FREE_PHPSTR_ALL(STR) phpstr_free(&(STR))
 #define FREE_PHPSTR(free, STR) \
        switch (free) \
        { \
+               case PHPSTR_FREE_NOT:                                           break; \
                case PHPSTR_FREE_PTR:   efree(STR);                     break; \
                case PHPSTR_FREE_VAL:   phpstr_dtor(STR);       break; \
-               case PHPSTR_FREE_ALL:   phpstr_free(STR);       break; \
-               case PHPSTR_FREE_NOT:                                           break; \
+               case PHPSTR_FREE_ALL: \
+               { \
+                       phpstr *PTR = (STR); \
+                       phpstr_free(&PTR); \
+               } \
+               break; \
                default:                                                                        break; \
        }
 
 #define RETURN_PHPSTR_PTR(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
-#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR(&(STR), PHPSTR_FREE_NOT, 0)
+#define RETURN_PHPSTR_VAL(STR) RETURN_PHPSTR((STR), PHPSTR_FREE_NOT, 0)
 #define RETVAL_PHPSTR_PTR(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_PTR, 0)
-#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR(&(STR), PHPSTR_FREE_NOT, 0)
+#define RETVAL_PHPSTR_VAL(STR) RETVAL_PHPSTR((STR), PHPSTR_FREE_NOT, 0)
 /* RETURN_PHPSTR(buf, PHPSTR_FREE_PTR, 0) */
 #define RETURN_PHPSTR(STR, free, dup) \
        RETVAL_PHPSTR((STR), (free), (dup)); \
@@ -136,7 +149,7 @@ PHPSTR_API void phpstr_fix(phpstr *buf);
 PHPSTR_API void phpstr_dtor(phpstr *buf);
 
 /* free a phpstr object completely */
-PHPSTR_API void phpstr_free(phpstr *buf);
+PHPSTR_API void phpstr_free(phpstr **buf);
 
 #endif
 
diff --git a/tests/split_response_001.phpt b/tests/split_response_001.phpt
deleted file mode 100644 (file)
index f3d73a5..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
---TEST--
-http_split_response()
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-echo "-TEST\n";
-$data = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nContent-Language: de-AT\r\nDate: Sat, 22 Jan 2005 18:10:02 GMT\r\n\r\nHallo Du!";
-var_export(http_split_response($data));
-echo "\nDone\n";
-?>
---EXPECTF--
-%sTEST
-array (
-  0 => 
-  array (
-    'Response Status' => '200 Ok',
-    'Content-Type' => 'text/plain',
-    'Content-Language' => 'de-AT',
-    'Date' => 'Sat, 22 Jan 2005 18:10:02 GMT',
-  ),
-  1 => 'Hallo Du!',
-)
-Done
-
diff --git a/tests/split_response_002.phpt b/tests/split_response_002.phpt
deleted file mode 100644 (file)
index 6db00dd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
---TEST--
-http_split_response() list bug (mem-leaks)
---SKIPIF--
-<?php
-include 'skip.inc';
-?>
---FILE--
-<?php
-echo "Try\n";
-$data = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nContent-Language: de-AT\r\nDate: Sat, 22 Jan 2005 18:10:02 GMT\r\n\r\nHallo Du!";
-class t { 
-       var $r = array(); 
-       function fail($data) {
-               list($this->r['headers'], $this->r['body']) = http_split_response($data);
-       }
-}
-
-$t = new t;
-$t->fail($data);
-echo "Done\n";
-?>
---EXPECTF--
-%sTry
-Done