X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=php_http_message.c;h=3141065f8353466ff9edb9003a0400397daa2ed3;hp=68ba91adb09ee207ec28ad894ce7f0fd58eb5fd2;hb=906ccdd174554232371d4f50db47e0817fd91789;hpb=847c94ac2eef3c43200a7e066a7ee823d580b20c diff --git a/php_http_message.c b/php_http_message.c index 68ba91a..3141065 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -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 | + | Copyright (c) 2004-2014, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -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; @@ -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) { @@ -251,7 +270,7 @@ 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; @@ -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,6 +319,14 @@ 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); } } @@ -321,10 +348,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 +366,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 +386,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 +409,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 +435,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 +453,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 +483,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); @@ -483,7 +510,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) { @@ -711,13 +738,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 +757,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 +791,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 +811,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 +937,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; + int verlen; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); - INIT_PZVAL_ARRAY(&array, props); #define ASSOC_PROP(ptype, n, val) \ @@ -933,20 +963,21 @@ 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); + verlen = spprintf(&version, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor); + ASSOC_STRINGL_EX("httpVersion", version, verlen, 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)); + ASSOC_STRING("requestUrl", STR_PTR(obj->message->http.info.request.url)); 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 +993,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,68 +1025,79 @@ 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); - 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); + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, s, flags, &msg)) { + if (!EG(exception)) { + php_http_throw(bad_message, "Could not parse message from stream", NULL); } } + + 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) - ZEND_ARG_INFO(0, body) + ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setBody) { @@ -1070,7 +1113,7 @@ static PHP_METHOD(HttpMessage, setBody) } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addBody, 0, 0, 1) - ZEND_ARG_INFO(0, body) + ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, addBody) { @@ -1123,7 +1166,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); } } } @@ -1172,7 +1215,7 @@ static PHP_METHOD(HttpMessage, setHeader) } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeaders, 0, 0, 1) - ZEND_ARG_INFO(0, headers) + ZEND_ARG_ARRAY_INFO(0, headers, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setHeaders) { @@ -1222,7 +1265,7 @@ static PHP_METHOD(HttpMessage, addHeader) } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeaders, 0, 0, 1) - ZEND_ARG_INFO(0, headers) + ZEND_ARG_ARRAY_INFO(0, headers, 0) ZEND_ARG_INFO(0, append) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, addHeaders) @@ -1293,7 +1336,6 @@ static PHP_METHOD(HttpMessage, getInfo) Z_TYPE_P(return_value) = IS_STRING; return; } - RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setInfo, 0, 0, 1) @@ -1303,17 +1345,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_info_parse(&inf, str TSRMLS_CC)) { - 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); - php_http_message_set_info(obj->message, &inf); - php_http_info_dtor(&inf); + 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); } @@ -1331,8 +1378,6 @@ static PHP_METHOD(HttpMessage, getHttpVersion) php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL TSRMLS_CC); RETURN_STRINGL(str, len, 0); } - - RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHttpVersion, 0, 0, 1) @@ -1342,17 +1387,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,34 +1411,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); } - RETURN_FALSE; } 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); - 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 (obj->message->type != PHP_HTTP_RESPONSE) { + php_http_throw(bad_method_call, "http\\Message is not of type response", NULL); + return; + } + + 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; + STR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code))); + RETVAL_ZVAL(getThis(), 1, 0); } @@ -1405,15 +1461,16 @@ 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 { RETURN_EMPTY_STRING(); } } - - RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseStatus, 0, 0, 1) @@ -1423,15 +1480,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_TYPE_CHECK(RESPONSE, obj->message, RETURN_FALSE); - STR_SET(obj->message->http.info.response.status, estrndup(status, status_len)); + 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); } + + STR_SET(obj->message->http.info.response.status, estrndup(status, status_len)); RETVAL_ZVAL(getThis(), 1, 0); } @@ -1444,15 +1505,17 @@ 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 { RETURN_EMPTY_STRING(); } } - - RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestMethod, 0, 0, 1) @@ -1462,20 +1525,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); - STR_SET(obj->message->http.info.request.method, estrndup(method, method_len)); + if (obj->message->type != PHP_HTTP_REQUEST) { + php_http_throw(bad_method_call, "http\\Message is not of type request", NULL); + return; } + + if (method_len < 1) { + php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string", NULL); + return; + } + + STR_SET(obj->message->http.info.request.method, estrndup(method, method_len)); RETVAL_ZVAL(getThis(), 1, 0); } @@ -1488,15 +1556,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); } else { RETURN_EMPTY_STRING(); } } - - RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1) @@ -1506,19 +1576,25 @@ static PHP_METHOD(HttpMessage, setRequestUrl) { char *url_str; int url_len; + php_http_message_object_t *obj; - 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, "s", &url_str, &url_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 (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; } + + if (url_len < 1) { + php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL); + return; + } + + STR_SET(obj->message->http.info.request.url, estrndup(url_str, url_len)); RETVAL_ZVAL(getThis(), 1, 0); } @@ -1526,19 +1602,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) @@ -1607,9 +1684,8 @@ static PHP_METHOD(HttpMessage, toCallback) zend_fcall_info_args_clear(&fcd.fci, 1); zval_ptr_dtor(&fcd.fcz); - RETURN_TRUE; + RETURN_ZVAL(getThis(), 1, 0); } - RETURN_FALSE; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_serialize, 0, 0, 0) @@ -1649,7 +1725,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"); } } } @@ -1658,57 +1734,56 @@ 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) ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0) + ZEND_ARG_INFO(0, top) ZEND_END_ARG_INFO(); 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_MESSAGE_OBJECT_INIT(obj); + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return); - if (!prepend_obj->message) { - prepend_obj->message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); - } - - /* 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) @@ -1737,28 +1812,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); + + STR_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); @@ -1767,7 +1849,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) @@ -1907,7 +1988,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;