ensure options are applied before the headers are set
[m6w6/ext-http] / php_http_message.c
index 1c337035cc7cac2c89e4e509c3b1f8f5226c4a2b..8a7e564a761990743270c2e7c736de49cc2471ce 100644 (file)
@@ -6,7 +6,7 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2013, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
@@ -14,7 +14,7 @@
 
 static void message_headers(php_http_message_t *msg, php_http_buffer_t *str);
 
-PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC)
+zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info TSRMLS_DC)
 {
        php_http_message_t *old = *message;
 
@@ -34,7 +34,7 @@ PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **messa
        return old != *message;
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type, php_http_message_body_t *body TSRMLS_DC)
+php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type, php_http_message_body_t *body TSRMLS_DC)
 {
        if (!message) {
                message = emalloc(sizeof(*message));
@@ -51,7 +51,7 @@ PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *messa
        return message;
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC)
+php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type TSRMLS_DC)
 {
        int free_msg = !message;
        zval *sval, tval;
@@ -69,7 +69,7 @@ PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m
                                message->http.info.request.method = estrdup(Z_STRVAL_P(sval));
                        }
                        if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1 TSRMLS_CC))) {
-                               message->http.info.request.url = estrdup(Z_STRVAL_P(sval));
+                               message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), ~0 TSRMLS_CC);
                        }
                        
                        php_http_env_get_request_headers(&message->hdrs TSRMLS_CC);
@@ -88,10 +88,23 @@ PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m
 #if PHP_VERSION_ID >= 50400
                        if (php_output_get_level(TSRMLS_C)) {
                                if (php_output_get_status(TSRMLS_C) & PHP_OUTPUT_SENT) {
-                                       php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(TSRMLS_C), php_output_get_start_lineno(TSRMLS_C));
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(TSRMLS_C), php_output_get_start_lineno(TSRMLS_C));
                                        goto error;
                                } else if (SUCCESS != php_output_get_contents(&tval TSRMLS_CC)) {
-                                       php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "Could not fetch response body");
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body");
+                                       goto error;
+                               } else {
+                                       php_http_message_body_append(message->body, Z_STRVAL(tval), Z_STRLEN(tval));
+                                       zval_dtor(&tval);
+                               }
+                       }
+#else
+                       if (OG(ob_nesting_level)) {
+                               if (php_get_output_start_filename(TSRMLS_C)) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_get_output_start_filename(TSRMLS_C), php_get_output_start_lineno(TSRMLS_C));
+                                       goto error;
+                               } else if (SUCCESS != php_ob_get_buffer(&tval TSRMLS_CC)) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch response body");
                                        goto error;
                                } else {
                                        php_http_message_body_append(message->body, Z_STRVAL(tval), Z_STRLEN(tval));
@@ -116,7 +129,7 @@ PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m
        return message;
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy TSRMLS_DC)
+php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy TSRMLS_DC)
 {
        php_http_message_parser_t p;
        php_http_buffer_t buf;
@@ -146,10 +159,16 @@ PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg,
        return msg;
 }
 
-PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len, int join)
+zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len, int join)
 {
        zval *ret = NULL, **header;
-       char *key = php_http_pretty_key(estrndup(key_str, key_len), key_len, 1, 1);
+       char *key;
+       ALLOCA_FLAG(free_key);
+
+       key = do_alloca(key_len + 1, free_key);
+       memcpy(key, key_str, key_len);
+       key[key_len] = '\0';
+       php_http_pretty_key(key, key_len, 1, 1);
 
        if (SUCCESS == zend_symtable_find(&msg->hdrs, key, key_len + 1, (void *) &header)) {
                if (join && Z_TYPE_PP(header) == IS_ARRAY) {
@@ -162,12 +181,12 @@ PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, const char *
                }
        }
 
-       efree(key);
+       free_alloca(key, free_key);
 
        return ret;
 }
 
-PHP_HTTP_API zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary)
+zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary)
 {
        zval *ct = php_http_message_header(msg, ZEND_STRL("Content-Type"), 1);
        zend_bool is_multipart = 0;
@@ -226,7 +245,7 @@ PHP_HTTP_API zend_bool php_http_message_is_multipart(php_http_message_t *msg, ch
 }
 
 /* */
-PHP_HTTP_API void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type)
+void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type)
 {
        /* just act if different */
        if (type != message->type) {
@@ -234,12 +253,12 @@ PHP_HTTP_API void php_http_message_set_type(php_http_message_t *message, php_htt
                /* free request info */
                switch (message->type) {
                        case PHP_HTTP_REQUEST:
-                               STR_FREE(message->http.info.request.method);
-                               STR_FREE(message->http.info.request.url);
+                               PTR_FREE(message->http.info.request.method);
+                               PTR_FREE(message->http.info.request.url);
                                break;
                        
                        case PHP_HTTP_RESPONSE:
-                               STR_FREE(message->http.info.response.status);
+                               PTR_FREE(message->http.info.response.status);
                                break;
                        
                        default:
@@ -251,19 +270,19 @@ PHP_HTTP_API void php_http_message_set_type(php_http_message_t *message, php_htt
        }
 }
 
-PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info)
+void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info)
 {
        php_http_message_set_type(message, info->type);
        message->http.version = info->http.version;
        switch (message->type) {
                case PHP_HTTP_REQUEST:
-                       STR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? estrdup(PHP_HTTP_INFO(info).request.url) : NULL);
-                       STR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL);
+                       PTR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? php_http_url_copy(PHP_HTTP_INFO(info).request.url, 0) : NULL);
+                       PTR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL);
                        break;
                
                case PHP_HTTP_RESPONSE:
                        PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code;
-                       STR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL);
+                       PTR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL);
                        break;
                
                default:
@@ -271,7 +290,7 @@ PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_htt
        }
 }
 
-PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg)
+void php_http_message_update_headers(php_http_message_t *msg)
 {
        zval *h;
        size_t size;
@@ -300,20 +319,31 @@ PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg)
                                zval_ptr_dtor(&h);
                        }
                }
+       } else if ((h = php_http_message_header(msg, ZEND_STRL("Content-Length"), 1))) {
+               zval *h_cpy = php_http_ztyp(IS_LONG, h);
+
+               zval_ptr_dtor(&h);
+               if (Z_LVAL_P(h_cpy)) {
+                       zend_hash_del(&msg->hdrs, "Content-Length", sizeof("Content-Length"));
+               }
+               zval_ptr_dtor(&h_cpy);
        }
 }
 
 static void message_headers(php_http_message_t *msg, php_http_buffer_t *str)
 {
+       char *tmp = NULL;
        TSRMLS_FETCH_FROM_CTX(msg->ts);
 
        switch (msg->type) {
                case PHP_HTTP_REQUEST:
-                       php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, PHP_HTTP_CRLF));
+                       php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF));
+                       PTR_FREE(tmp);
                        break;
 
                case PHP_HTTP_RESPONSE:
-                       php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, PHP_HTTP_CRLF));
+                       php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF));
+                       PTR_FREE(tmp);
                        break;
 
                default:
@@ -321,10 +351,10 @@ static void message_headers(php_http_message_t *msg, php_http_buffer_t *str)
        }
 
        php_http_message_update_headers(msg);
-       php_http_headers_to_string(str, &msg->hdrs TSRMLS_CC);
+       php_http_header_to_string(str, &msg->hdrs TSRMLS_CC);
 }
 
-PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg)
+void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg)
 {
        php_http_buffer_t str;
 
@@ -339,7 +369,7 @@ PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http
        }
 }
 
-PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length)
+void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length)
 {
        php_http_buffer_t str;
        char *data;
@@ -359,7 +389,7 @@ PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **str
        php_http_buffer_dtor(&str);
 }
 
-PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length)
+void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length)
 {
        char *buf;
        php_http_buffer_t str;
@@ -382,7 +412,7 @@ PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char *
        php_http_buffer_dtor(&str);
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg)
+php_http_message_t *php_http_message_reverse(php_http_message_t *msg)
 {
        int i, c = 0;
        
@@ -408,7 +438,7 @@ PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *ms
        return msg;
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two)
+php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two)
 {
        php_http_message_t *dst = php_http_message_copy(one, NULL), *src = php_http_message_copy(two, NULL), *tmp_dst, *tmp_src, *ret = dst;
 
@@ -426,7 +456,7 @@ PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, p
        return ret;
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents)
+php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents)
 {
        php_http_message_t *temp, *copy = NULL;
        php_http_info_t info;
@@ -456,12 +486,12 @@ PHP_HTTP_API php_http_message_t *php_http_message_copy_ex(php_http_message_t *fr
        return copy;
 }
 
-PHP_HTTP_API php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to)
+php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to)
 {
        return php_http_message_copy_ex(from, to, 1);
 }
 
-PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message)
+void php_http_message_dtor(php_http_message_t *message)
 {
        if (message) {
                zend_hash_destroy(&message->hdrs);
@@ -469,12 +499,12 @@ PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message)
                
                switch (message->type) {
                        case PHP_HTTP_REQUEST:
-                               STR_SET(message->http.info.request.method, NULL);
-                               STR_SET(message->http.info.request.url, NULL);
+                               PTR_SET(message->http.info.request.method, NULL);
+                               PTR_SET(message->http.info.request.url, NULL);
                                break;
                        
                        case PHP_HTTP_RESPONSE:
-                               STR_SET(message->http.info.response.status, NULL);
+                               PTR_SET(message->http.info.response.status, NULL);
                                break;
                        
                        default:
@@ -483,7 +513,7 @@ PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message)
        }
 }
 
-PHP_HTTP_API void php_http_message_free(php_http_message_t **message)
+void php_http_message_free(php_http_message_t **message)
 {
        if (*message) {
                if ((*message)->parent) {
@@ -534,22 +564,23 @@ static void php_http_message_object_prophandler_get_request_method(php_http_mess
 static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
        if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
                zval *cpy = php_http_ztyp(IS_STRING, value);
-               STR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
+               PTR_SET(obj->message->http.info.request.method, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
                zval_ptr_dtor(&cpy);
        }
 }
 static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
-       if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) {
-               RETVAL_STRING(obj->message->http.info.request.url, 1);
+       char *url_str;
+       size_t url_len;
+
+       if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url && php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0)) {
+               RETVAL_STRINGL(url_str, url_len, 0);
        } else {
                RETVAL_NULL();
        }
 }
 static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
        if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
-               zval *cpy = php_http_ztyp(IS_STRING, value);
-               STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
-               zval_ptr_dtor(&cpy);
+               PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, ~0 TSRMLS_CC));
        }
 }
 static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) {
@@ -562,7 +593,7 @@ static void php_http_message_object_prophandler_get_response_status(php_http_mes
 static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value TSRMLS_DC) {
        if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
                zval *cpy = php_http_ztyp(IS_STRING, value);
-               STR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
+               PTR_SET(obj->message->http.info.response.status, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy)));
                zval_ptr_dtor(&cpy);
        }
 }
@@ -577,7 +608,7 @@ static void php_http_message_object_prophandler_set_response_code(php_http_messa
        if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
                zval *cpy = php_http_ztyp(IS_LONG, value);
                obj->message->http.info.response.code = Z_LVAL_P(cpy);
-               STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code)));
+               PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code)));
                zval_ptr_dtor(&cpy);
        }
 }
@@ -711,13 +742,7 @@ void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool to
 
        /* add ref */
        zend_objects_store_add_ref(prepend TSRMLS_CC);
-       /*
-       while (prepend_obj->parent) {
-               m.value.obj = prepend_obj->parent->zv;
-               zend_objects_store_add_ref(&m TSRMLS_CC);
-               prepend_obj = zend_object_store_get_object(&m TSRMLS_CC);
-       }
-       */
+
        if (!top) {
                prepend_obj->parent = save_parent_obj;
                prepend_obj->message->parent = save_parent_msg;
@@ -736,7 +761,7 @@ STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval
                case IS_RESOURCE:
                        php_stream_from_zval_no_verify(s, &zbody);
                        if (!s) {
-                               php_http_error(HE_THROW, PHP_HTTP_E_CLIENT, "not a valid stream resource");
+                               php_http_throw(unexpected_val, "The stream is not a valid resource", NULL);
                                return FAILURE;
                        }
 
@@ -770,7 +795,9 @@ STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval
        }
 
        body_obj = zend_object_store_get_object(zbody TSRMLS_CC);
-
+       if (!body_obj->body) {
+               body_obj->body = php_http_message_body_init(NULL, NULL TSRMLS_CC);
+       }
        if (msg_obj->body) {
                zend_objects_store_del_ref_by_handle(msg_obj->body->zv.handle TSRMLS_CC);
        }
@@ -788,6 +815,14 @@ STATUS php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval
        return SUCCESS;
 }
 
+STATUS php_http_message_object_init_body_object(php_http_message_object_t *obj)
+{
+       TSRMLS_FETCH_FROM_CTX(obj->message->ts);
+
+       php_http_message_body_addref(obj->message->body);
+       return php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body, (void *) &obj->body TSRMLS_CC);
+}
+
 zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC)
 {
        return php_http_message_object_new_ex(ce, NULL, NULL TSRMLS_CC);
@@ -906,13 +941,12 @@ static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC)
 {
        zval *headers;
        php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
-       php_http_message_t *msg = obj->message;
        HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC);
        zval array, *parent, *body;
-       char *version;
+       char *ver_str, *url_str = NULL;
+       size_t ver_len, url_len = 0;
 
        PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
-       
        INIT_PZVAL_ARRAY(&array, props);
        
 #define ASSOC_PROP(ptype, n, val) \
@@ -933,20 +967,27 @@ static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC)
                } \
        } while(0)
 
-       ASSOC_PROP(long, "type", msg->type);
-       ASSOC_STRINGL_EX("httpVersion", version, spprintf(&version, 0, "%u.%u", msg->http.version.major, msg->http.version.minor), 0);
+       ASSOC_PROP(long, "type", obj->message->type);
+       ver_len = spprintf(&ver_str, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor);
+       ASSOC_STRINGL_EX("httpVersion", ver_str, ver_len, 0);
 
-       switch (msg->type) {
+       switch (obj->message->type) {
                case PHP_HTTP_REQUEST:
                        ASSOC_PROP(long, "responseCode", 0);
                        ASSOC_STRINGL("responseStatus", "", 0);
-                       ASSOC_STRING("requestMethod", STR_PTR(msg->http.info.request.method));
-                       ASSOC_STRING("requestUrl", STR_PTR(msg->http.info.request.url));
+                       ASSOC_STRING("requestMethod", STR_PTR(obj->message->http.info.request.method));
+                       if (obj->message->http.info.request.url) {
+                               php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
+                               ASSOC_STRINGL_EX("requestUrl", url_str, url_len, 0);
+                       } else {
+                               ASSOC_STRINGL("requestUrl", "", 0);
+                       }
+
                        break;
 
                case PHP_HTTP_RESPONSE:
-                       ASSOC_PROP(long, "responseCode", msg->http.info.response.code);
-                       ASSOC_STRING("responseStatus", STR_PTR(msg->http.info.response.status));
+                       ASSOC_PROP(long, "responseCode", obj->message->http.info.response.code);
+                       ASSOC_STRING("responseStatus", STR_PTR(obj->message->http.info.response.status));
                        ASSOC_STRINGL("requestMethod", "", 0);
                        ASSOC_STRINGL("requestUrl", "", 0);
                        break;
@@ -962,18 +1003,19 @@ static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC)
 
        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 *));
+       zend_hash_copy(Z_ARRVAL_P(headers), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
        ASSOC_PROP(zval, "headers", headers);
 
        MAKE_STD_ZVAL(body);
-       if (!obj->body) {
-               php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, (void *) php_http_message_body_init(&obj->message->body, NULL TSRMLS_CC), (void *) &obj->body TSRMLS_CC);
+       if (obj->body) {
+               ZVAL_OBJVAL(body, obj->body->zv, 1);
+       } else {
+               ZVAL_NULL(body);
        }
-       ZVAL_OBJVAL(body, obj->body->zv, 1);
        ASSOC_PROP(zval, "body", body);
 
        MAKE_STD_ZVAL(parent);
-       if (msg->parent) {
+       if (obj->message->parent) {
                ZVAL_OBJVAL(parent, obj->parent->zv, 1);
        } else {
                ZVAL_NULL(parent);
@@ -993,64 +1035,77 @@ static PHP_METHOD(HttpMessage, __construct)
        zval *zmessage = NULL;
        php_http_message_t *msg = NULL;
        php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       zend_error_handling zeh;
 
-       with_error_handling(EH_THROW, php_http_exception_class_entry) {
-               if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!b", &zmessage, &greedy) && zmessage) {
-                       if (Z_TYPE_P(zmessage) == IS_RESOURCE) {
-                               php_stream *s;
-                               php_http_message_parser_t p;
-
-                               php_stream_from_zval(s, &zmessage);
-                               if (s && php_http_message_parser_init(&p TSRMLS_CC)) {
-                                       unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0);
-                                       
-                                       php_http_message_parser_parse_stream(&p, s, flags, &msg);
-                                       php_http_message_parser_dtor(&p);
-                               }
-                               
-                               if (!msg) {
-                                       php_http_error(HE_THROW, PHP_HTTP_E_MESSAGE, "could not parse message from stream");
-                               }
-                       } else {
-                               zmessage = php_http_ztyp(IS_STRING, zmessage);
-                               if (!(msg = php_http_message_parse(NULL, Z_STRVAL_P(zmessage), Z_STRLEN_P(zmessage), greedy TSRMLS_CC))) {
-                                       php_http_error(HE_THROW, PHP_HTTP_E_MESSAGE, "could not parse message: %.*s", MIN(25, Z_STRLEN_P(zmessage)), Z_STRVAL_P(zmessage));
-                               }
-                               zval_ptr_dtor(&zmessage);
-                       }
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!b", &zmessage, &greedy), invalid_arg, return);
+
+       zend_replace_error_handling(EH_THROW, php_http_exception_bad_message_class_entry, &zeh TSRMLS_CC);
+       if (zmessage && Z_TYPE_P(zmessage) == IS_RESOURCE) {
+               php_stream *s;
+               php_http_message_parser_t p;
+               zend_error_handling zeh;
+
+               zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh TSRMLS_CC);
+               php_stream_from_zval(s, &zmessage);
+               zend_restore_error_handling(&zeh TSRMLS_CC);
+
+               if (s && php_http_message_parser_init(&p TSRMLS_CC)) {
+                       unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0);
+                       php_http_buffer_t buf;
 
-                       if (msg) {
-                               php_http_message_dtor(obj->message);
-                               obj->message = msg;
-                               if (obj->message->parent) {
-                                       php_http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, &obj->parent TSRMLS_CC);
+                       php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC);
+                       if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, &buf, s, flags, &msg)) {
+                               if (!EG(exception)) {
+                                       php_http_throw(bad_message, "Could not parse message from stream", NULL);
                                }
                        }
+                       php_http_buffer_dtor(&buf);
+                       php_http_message_parser_dtor(&p);
                }
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
-       } end_error_handling();
 
+               if (!msg && !EG(exception)) {
+                       php_http_throw(bad_message, "Empty message received from stream", NULL);
+               }
+       } else if (zmessage) {
+               zmessage = php_http_ztyp(IS_STRING, zmessage);
+               msg = php_http_message_parse(NULL, Z_STRVAL_P(zmessage), Z_STRLEN_P(zmessage), greedy TSRMLS_CC);
+
+               if (!msg && !EG(exception)) {
+                       php_http_throw(bad_message, "Could not parse message: %.*s", MIN(25, Z_STRLEN_P(zmessage)), Z_STRVAL_P(zmessage));
+               }
+               zval_ptr_dtor(&zmessage);
+       }
+
+       if (msg) {
+               php_http_message_dtor(obj->message);
+               obj->message = msg;
+               if (obj->message->parent) {
+                       php_http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, &obj->parent TSRMLS_CC);
+               }
+       }
+       zend_restore_error_handling(&zeh TSRMLS_CC);
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getBody, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, getBody)
 {
-       with_error_handling(EH_THROW, php_http_exception_class_entry) {
-               if (SUCCESS == zend_parse_parameters_none()) {
-                       php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_message_object_t *obj;
 
-                       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
 
-                       if (!obj->body) {
-                               php_http_message_body_addref(obj->message->body);
-                               php_http_new(NULL, php_http_message_body_class_entry, (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body, (void *) &obj->body TSRMLS_CC);
-                       }
-                       if (obj->body) {
-                               RETVAL_OBJVAL(obj->body->zv, 1);
-                       }
-               }
-       } end_error_handling();
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       if (!obj->body) {
+               php_http_message_object_init_body_object(obj);
+
+       }
+       if (obj->body) {
+               RETVAL_OBJVAL(obj->body->zv, 1);
+       }
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setBody, 0, 0, 1)
@@ -1123,7 +1178,7 @@ static PHP_METHOD(HttpMessage, getHeader)
 
                                return;
                        } else {
-                               php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Class '%s' is not as descendant of http\\Header", header_ce->name);
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class '%s' is not as descendant of http\\Header", header_ce->name);
                        }
                }
        }
@@ -1275,16 +1330,19 @@ ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, getInfo)
 {
        if (SUCCESS == zend_parse_parameters_none()) {
+               char *tmp = NULL;
                php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
                PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
                switch (obj->message->type) {
                        case PHP_HTTP_REQUEST:
-                               Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, ""));
+                               Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, tmp, ""));
+                               PTR_FREE(tmp);
                                break;
                        case PHP_HTTP_RESPONSE:
-                               Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, ""));
+                               Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, tmp, ""));
+                               PTR_FREE(tmp);
                                break;
                        default:
                                RETURN_NULL();
@@ -1302,20 +1360,22 @@ static PHP_METHOD(HttpMessage, setInfo)
 {
        char *str;
        int len;
+       php_http_message_object_t *obj;
        php_http_info_t inf;
 
-       if (    SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
-               if (php_http_info_parse(&inf, str TSRMLS_CC)) {
-                       php_http_message_set_info(obj->message, &inf);
-                       php_http_info_dtor(&inf);
-               } else {
-                       php_http_error(HE_WARNING, PHP_HTTP_E_MALFORMED_HEADERS, "Could not parse message info '%s'", str);
-               }
+       if (!php_http_info_parse(&inf, str TSRMLS_CC)) {
+               php_http_throw(bad_header, "Could not parse message info '%s'", str);
+               return;
        }
+
+       php_http_message_set_info(obj->message, &inf);
+       php_http_info_dtor(&inf);
+
        RETVAL_ZVAL(getThis(), 1, 0);
 }
 
@@ -1342,17 +1402,18 @@ static PHP_METHOD(HttpMessage, setHttpVersion)
 {
        char *v_str;
        int v_len;
+       php_http_version_t version;
+       php_http_message_object_t *obj;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &v_str, &v_len)) {
-               php_http_version_t version;
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &v_str, &v_len), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       php_http_expect(php_http_version_parse(&version, v_str TSRMLS_CC), unexpected_val, return);
+
+       obj->message->http.version = version;
 
-               if (php_http_version_parse(&version, v_str TSRMLS_CC)) {
-                       obj->message->http.version = version;
-               }
-       }
        RETVAL_ZVAL(getThis(), 1, 0);
 }
 
@@ -1365,33 +1426,44 @@ static PHP_METHOD(HttpMessage, getResponseCode)
 
                PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
+               if (obj->message->type != PHP_HTTP_RESPONSE) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not if type response");
+                       RETURN_FALSE;
+               }
+
                RETURN_LONG(obj->message->http.info.response.code);
        }
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseCode, 0, 0, 1)
        ZEND_ARG_INFO(0, response_code)
+       ZEND_ARG_INFO(0, strict)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, setResponseCode)
 {
        long code;
        zend_bool strict = 1;
+       php_http_message_object_t *obj;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &code, &strict)) {
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &code, &strict), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
-               if (strict && (code < 100 || code > 599)) {
-                       php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Invalid response code (100-599): %ld", code);
-                       RETURN_FALSE;
-               }
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       if (obj->message->type != PHP_HTTP_RESPONSE) {
+               php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
+               return;
+       }
 
-               obj->message->http.info.response.code = code;
-               STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code)));
+       if (strict && (code < 100 || code > 599)) {
+               php_http_throw(invalid_arg, "Invalid response code (100-599): %ld", code);
+               return;
        }
+
+       obj->message->http.info.response.code = code;
+       PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code)));
+
        RETVAL_ZVAL(getThis(), 1, 0);
 }
 
@@ -1404,7 +1476,10 @@ static PHP_METHOD(HttpMessage, getResponseStatus)
 
                PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
+               if (obj->message->type != PHP_HTTP_RESPONSE) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not of type response");
+               }
+
                if (obj->message->http.info.response.status) {
                        RETURN_STRING(obj->message->http.info.response.status, 1);
                } else {
@@ -1420,15 +1495,19 @@ static PHP_METHOD(HttpMessage, setResponseStatus)
 {
        char *status;
        int status_len;
+       php_http_message_object_t *obj;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) {
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE);
-               STR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
+       if (obj->message->type != PHP_HTTP_RESPONSE) {
+               php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
        }
+
+       PTR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
        RETVAL_ZVAL(getThis(), 1, 0);
 }
 
@@ -1441,7 +1520,11 @@ static PHP_METHOD(HttpMessage, getRequestMethod)
 
                PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
+               if (obj->message->type != PHP_HTTP_REQUEST) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not of type request");
+                       RETURN_FALSE;
+               }
+
                if (obj->message->http.info.request.method) {
                        RETURN_STRING(obj->message->http.info.request.method, 1);
                } else {
@@ -1457,20 +1540,25 @@ static PHP_METHOD(HttpMessage, setRequestMethod)
 {
        char *method;
        int method_len;
+       php_http_message_object_t *obj;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
-               if (method_len < 1) {
-                       php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
-                       RETURN_FALSE;
-               }
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       if (obj->message->type != PHP_HTTP_REQUEST) {
+               php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
+               return;
+       }
 
-               STR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
+       if (method_len < 1) {
+               php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string", NULL);
+               return;
        }
+
+       PTR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
        RETVAL_ZVAL(getThis(), 1, 0);
 }
 
@@ -1483,9 +1571,17 @@ static PHP_METHOD(HttpMessage, getRequestUrl)
 
                PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
+               if (obj->message->type != PHP_HTTP_REQUEST) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "http\\Message is not of type request");
+                       RETURN_FALSE;
+               }
+
                if (obj->message->http.info.request.url) {
-                       RETURN_STRING(obj->message->http.info.request.url, 1);
+                       char *url_str;
+                       size_t url_len;
+
+                       php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
+                       RETURN_STRINGL(url_str, url_len, 0);
                } else {
                        RETURN_EMPTY_STRING();
                }
@@ -1497,21 +1593,33 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, setRequestUrl)
 {
-       char *url_str;
-       int url_len;
+       zval *zurl;
+       php_http_url_t *url;
+       php_http_message_object_t *obj;
+       zend_error_handling zeh;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url_str, &url_len)) {
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zurl), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
-               PHP_HTTP_MESSAGE_TYPE_CHECK(REQUEST, obj->message, RETURN_FALSE);
-               if (url_len < 1) {
-                       php_http_error(HE_WARNING, PHP_HTTP_E_INVALID_PARAM, "Cannot set HttpMessage::requestUrl to an empty string");
-                       RETURN_FALSE;
-               }
-               STR_SET(obj->message->http.info.request.url, estrndup(url_str, url_len));
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       if (obj->message->type != PHP_HTTP_REQUEST) {
+               php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
+               return;
+       }
+
+       zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC);
+       url = php_http_url_from_zval(zurl, ~0 TSRMLS_CC);
+       zend_restore_error_handling(&zeh TSRMLS_CC);
+
+       if (php_http_url_is_empty(url)) {
+               php_http_url_free(&url);
+               php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL);
+       } else {
+               PTR_SET(obj->message->http.info.request.url, url);
        }
+
        RETVAL_ZVAL(getThis(), 1, 0);
 }
 
@@ -1519,19 +1627,20 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getParentMessage, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, getParentMessage)
 {
-       with_error_handling(EH_THROW, php_http_exception_class_entry) {
-               if (SUCCESS == zend_parse_parameters_none()) {
-                       php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_message_object_t *obj;
 
-                       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
 
-                       if (obj->message->parent) {
-                               RETVAL_OBJVAL(obj->parent->zv, 1);
-                       } else {
-                               php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpMessage does not have a parent message");
-                       }
-               }
-       } end_error_handling();
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       if (!obj->message->parent) {
+               php_http_throw(unexpected_val, "http\\Message has not parent message", NULL);
+               return;
+       }
+
+       RETVAL_OBJVAL(obj->parent->zv, 1);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___toString, 0, 0, 0)
@@ -1641,7 +1750,7 @@ static PHP_METHOD(HttpMessage, unserialize)
                        obj->message = msg;
                } else {
                        obj->message = php_http_message_init(NULL, 0, NULL TSRMLS_CC);
-                       php_http_error(HE_ERROR, PHP_HTTP_E_RUNTIME, "Could not unserialize HttpMessage");
+                       php_error_docref(NULL TSRMLS_CC, E_ERROR, "Could not unserialize http\\Message");
                }
        }
 }
@@ -1650,15 +1759,15 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_detach, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, detach)
 {
-       with_error_handling(EH_THROW, php_http_exception_class_entry) {
-               if (SUCCESS == zend_parse_parameters_none()) {
-                       php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_http_message_object_t *obj;
 
-                       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
 
-                       RETVAL_OBJVAL(php_http_message_object_new_ex(obj->zo.ce, php_http_message_copy_ex(obj->message, NULL, 0), NULL TSRMLS_CC), 0);
-               }
-       } end_error_handling();
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       RETVAL_OBJVAL(php_http_message_object_new_ex(obj->zo.ce, php_http_message_copy_ex(obj->message, NULL, 0), NULL TSRMLS_CC), 0);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_prepend, 0, 0, 1)
@@ -1669,36 +1778,37 @@ static PHP_METHOD(HttpMessage, prepend)
 {
        zval *prepend;
        zend_bool top = 1;
+       php_http_message_t *msg[2];
+       php_http_message_object_t *obj, *prepend_obj;
 
-       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, php_http_message_class_entry, &top)) {
-               php_http_message_t *msg[2];
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
-               php_http_message_object_t *prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC);
+       php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return);
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
-               PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj);
-
-               /* safety check */
-               for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
-                       for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
-                               if (msg[0] == msg[1]) {
-                                       php_http_error(HE_THROW, PHP_HTTP_E_INVALID_PARAM, "Cannot prepend a message located within the same message chain");
-                                       return;
-                               }
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       prepend_obj = zend_object_store_get_object(prepend TSRMLS_CC);
+       PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj);
+
+       /* safety check */
+       for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
+               for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
+                       if (msg[0] == msg[1]) {
+                               php_http_throw(unexpected_val, "Cannot prepend a message located within the same message chain", NULL);
+                               return;
                        }
                }
-
-               php_http_message_object_prepend(getThis(), prepend, top TSRMLS_CC);
        }
+
+       php_http_message_object_prepend(getThis(), prepend, top TSRMLS_CC);
+       RETURN_ZVAL(getThis(), 1, 0);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_reverse, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, reverse)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
-               php_http_message_object_reverse(getThis(), return_value TSRMLS_CC);
-       }
+       php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
+
+       php_http_message_object_reverse(getThis(), return_value TSRMLS_CC);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_isMultipart, 0, 0, 0)
@@ -1727,28 +1837,35 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_splitMultipartBody, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, splitMultipartBody)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
-               php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
-               char *boundary = NULL;
+       php_http_message_object_t *obj;
+       php_http_message_t *msg;
+       char *boundary = NULL;
 
-               PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+       php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
 
-               if (php_http_message_is_multipart(obj->message, &boundary)) {
-                       php_http_message_t *msg;
+       obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
-                       if ((msg = php_http_message_body_split(obj->message->body, boundary))) {
-                               RETVAL_OBJVAL(php_http_message_object_new_ex(php_http_message_class_entry, msg, NULL TSRMLS_CC), 0);
-                       }
-               }
-               STR_FREE(boundary);
+       PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
+
+       if (!php_http_message_is_multipart(obj->message, &boundary)) {
+               php_http_throw(bad_method_call, "http\\Message is not a multipart message", NULL);
+               return;
        }
+
+       php_http_expect(msg = php_http_message_body_split(obj->message->body, boundary), bad_message, return);
+
+       PTR_FREE(boundary);
+
+       RETURN_OBJVAL(php_http_message_object_new_ex(php_http_message_class_entry, msg, NULL TSRMLS_CC), 0);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_count, 0, 0, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(HttpMessage, count)
 {
-       if (SUCCESS == zend_parse_parameters_none()) {
+       long count_mode = -1;
+
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &count_mode)) {
                long i = 0;
                php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 
@@ -1757,7 +1874,6 @@ static PHP_METHOD(HttpMessage, count)
                php_http_message_count(i, obj->message);
                RETURN_LONG(i);
        }
-       RETURN_FALSE;
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_rewind, 0, 0, 0)
@@ -1897,7 +2013,7 @@ PHP_MINIT_FUNCTION(http_message)
        zend_class_entry ce = {0};
 
        INIT_NS_CLASS_ENTRY(ce, "http", "Message", php_http_message_methods);
-       php_http_message_class_entry = zend_register_internal_class_ex(&ce, php_http_object_class_entry, NULL TSRMLS_CC);
+       php_http_message_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
        php_http_message_class_entry->create_object = php_http_message_object_new;
        memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
        php_http_message_object_handlers.clone_obj = php_http_message_object_clone;