From: Michael Wallner Date: Sun, 8 Feb 2015 15:23:13 +0000 (+0100) Subject: Merge branch 'master' into phpng X-Git-Tag: RELEASE_3_0_0_RC1~64 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=be9585b914061f84c5d5939673d29ecc048ab1d7 Merge branch 'master' into phpng Conflicts: php_http_client.c php_http_client.h php_http_client_curl.c php_http_env_response.c php_http_info.c php_http_message.c php_http_object.c php_http_object.h php_http_url.c php_http_url.h --- be9585b914061f84c5d5939673d29ecc048ab1d7 diff --cc php_http_buffer.c index 059db06,e24a4e1..b84bcd0 --- a/php_http_buffer.c +++ b/php_http_buffer.c @@@ -78,13 -72,9 +78,10 @@@ PHP_HTTP_BUFFER_API size_t php_http_buf return 0; } -PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account) +PHP_HTTP_BUFFER_API char *php_http_buffer_account( + php_http_buffer_t *buf, size_t to_account) { - /* it's probably already too late but check anyway */ - if (to_account > buf->free) { - return NULL; - } + assert(to_account <= buf->free); buf->free -= to_account; buf->used += to_account; diff --cc php_http_client.c index 66afb7c,3050bd8..4e55356 --- a/php_http_client.c +++ b/php_http_client.c @@@ -321,21 -324,24 +321,23 @@@ ZEND_RESULT_CODE php_http_client_getopt zend_class_entry *php_http_client_class_entry; static zend_object_handlers php_http_client_object_handlers; -void php_http_client_object_free(void *object TSRMLS_DC) +void php_http_client_object_free(zend_object *object) { - php_http_client_object_t *o = (php_http_client_object_t *) object; + php_http_client_object_t *o = PHP_HTTP_OBJ(object, NULL); php_http_client_free(&o->client); + php_http_object_method_dtor(&o->notify); + php_http_object_method_free(&o->update); - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(o); + zend_object_std_dtor(object); } -zend_object_value php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client, php_http_client_object_t **ptr TSRMLS_DC) +php_http_client_object_t *php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client) { php_http_client_object_t *o; - o = ecalloc(1, sizeof(php_http_client_object_t) + (ce->default_properties_count - 1) * sizeof(zval)); - o = ecalloc(1, sizeof(php_http_client_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); o->client = client; @@@ -367,7 -377,7 +369,7 @@@ static void handle_history(zval *zclien zval_ptr_dtor(&new_hist); } - static ZEND_RESULT_CODE handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response) -static STATUS handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **response) ++static ZEND_RESULT_CODE handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **response) { zend_bool dequeue = 0; zval zclient; @@@ -384,8 -396,8 +386,8 @@@ /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */ php_http_message_set_type(msg, PHP_HTTP_RESPONSE); - if (z_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) { - handle_history(&zclient, e->request, *response TSRMLS_CC); + if (zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0, &rec_hist_tmp))) { - handle_history(&zclient, *request, *response); ++ handle_history(&zclient, e->request, *response); } /* hard detach, redirects etc. are in the history */ @@@ -443,27 -459,36 +445,28 @@@ static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress) { - zval zrequest, zprogress, retval, zclient; - zval *zrequest, *zprogress, *zclient, **args[2]; ++ zval zclient, args[2]; + php_http_client_object_t *client_obj = arg; zend_error_handling zeh; - TSRMLS_FETCH_FROM_CTX(client->ts); - - MAKE_STD_ZVAL(zclient); - ZVAL_OBJVAL(zclient, client_obj->zv, 1); - - MAKE_STD_ZVAL(zrequest); - ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1); - args[0] = &zrequest; - - MAKE_STD_ZVAL(zprogress); - object_init(zprogress); - add_property_bool(zprogress, "started", progress->started); - add_property_bool(zprogress, "finished", progress->finished); - add_property_string(zprogress, "info", STR_PTR(progress->info), 1); - add_property_double(zprogress, "dltotal", progress->dl.total); - add_property_double(zprogress, "dlnow", progress->dl.now); - add_property_double(zprogress, "ultotal", progress->ul.total); - add_property_double(zprogress, "ulnow", progress->ul.now); - args[1] = &zprogress; - - zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); - php_http_object_method_call(&client_obj->notify, zclient, NULL, 2, args TSRMLS_CC); - zend_restore_error_handling(&zeh TSRMLS_CC); + - ZVAL_UNDEF(&retval); - ZVAL_OBJECT(&zclient, &((php_http_client_object_t *) arg)->zo, 1); - ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1); - object_init(&zprogress); - add_property_bool(&zprogress, "started", progress->started); - add_property_bool(&zprogress, "finished", progress->finished); - add_property_string(&zprogress, "info", STR_PTR(progress->info)); - add_property_double(&zprogress, "dltotal", progress->dl.total); - add_property_double(&zprogress, "dlnow", progress->dl.now); - add_property_double(&zprogress, "ultotal", progress->ul.total); - add_property_double(&zprogress, "ulnow", progress->ul.now); ++ ZVAL_OBJECT(&zclient, &client_obj->zo, 1); ++ ZVAL_OBJECT(&args[0], &((php_http_message_object_t *) e->opaque)->zo, 1); ++ object_init(&args[1]); ++ add_property_bool(&args[1], "started", progress->started); ++ add_property_bool(&args[1], "finished", progress->finished); ++ add_property_string(&args[1], "info", STR_PTR(progress->info)); ++ add_property_double(&args[1], "dltotal", progress->dl.total); ++ add_property_double(&args[1], "dlnow", progress->dl.now); ++ add_property_double(&args[1], "ultotal", progress->ul.total); ++ add_property_double(&args[1], "ulnow", progress->ul.now); ++ + zend_replace_error_handling(EH_NORMAL, NULL, &zeh); - zend_call_method_with_2_params(&zclient, NULL, NULL, "notify", &retval, &zrequest, &zprogress); ++ php_http_object_method_call(&client_obj->notify, &zclient, NULL, 2, args); + zend_restore_error_handling(&zeh); + zval_ptr_dtor(&zclient); -- zval_ptr_dtor(&zrequest); -- zval_ptr_dtor(&zprogress); - zval_ptr_dtor(&retval); ++ zval_ptr_dtor(&args[0]); ++ zval_ptr_dtor(&args[1]); } static void response_dtor(void *data) @@@ -496,22 -519,32 +499,24 @@@ static PHP_METHOD(HttpClient, __constru return; } - MAKE_STD_ZVAL(os); - object_init_ex(os, spl_ce_SplObjectStorage); - zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC); + object_init_ex(&os, spl_ce_SplObjectStorage); + zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), &os); zval_ptr_dtor(&os); - if (persistent_handle_len) { - char *name_str; - size_t name_len; + if (persistent_handle_name) { php_persistent_handle_factory_t *pf; - name_len = spprintf(&name_str, 0, "http\\Client\\%s", driver.name_str); - php_http_pretty_key(name_str + sizeof("http\\Client"), driver.name_len, 1, 1); - - if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, persistent_handle_str, persistent_handle_len, NULL, NULL TSRMLS_CC))) { + if ((pf = php_persistent_handle_concede(NULL, driver->client_name, persistent_handle_name, NULL, NULL))) { rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon); } - - efree(name_str); } - obj = zend_object_store_get_object(getThis() TSRMLS_CC); + obj = PHP_HTTP_OBJ(NULL, getThis()); - php_http_expect(obj->client = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC), runtime, return); + php_http_expect(obj->client = php_http_client_init(NULL, driver->client_ops, rf, NULL), runtime, return); - php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify") TSRMLS_CC); ++ php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify")); + obj->client->callback.response.func = handle_response; obj->client->callback.response.arg = obj; obj->client->callback.progress.func = handle_progress; @@@ -840,16 -874,23 +845,22 @@@ static PHP_METHOD(HttpClient, enableEve php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return); - RETVAL_ZVAL(getThis(), 1, 0); + RETVAL_ZVAL_FAST(getThis()); } + struct notify_arg { + php_http_object_method_t *cb; - zval **args[3]; ++ zval args[3]; + int argc; + }; + -static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC) +static int notify(zend_object_iterator *iter, void *puser) { - zval *observer, *args = puser; - zval **observer = NULL; ++ zval *observer; + struct notify_arg *arg = puser; - iter->funcs->get_current_data(iter, &observer TSRMLS_CC); - if (observer) { - return php_http_object_method_call(arg->cb, *observer, NULL, arg->argc, arg->args TSRMLS_CC); + if ((observer = iter->funcs->get_current_data(iter))) { - int num_args = !Z_ISUNDEF(args[0]) + !Z_ISUNDEF(args[1]) + !Z_ISUNDEF(args[2]); - return php_http_method_call(observer, ZEND_STRL("update"), num_args, args, NULL); ++ return php_http_object_method_call(arg->cb, observer, NULL, arg->argc, arg->args); } return FAILURE; } @@@ -859,40 -900,51 +870,46 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_no ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, notify) { - zval *request = NULL, *zprogress = NULL, observers_tmp, *observers, args[3]; - zval *request = NULL, *zprogress = NULL, *observers; ++ zval *request = NULL, *zprogress = NULL, observers_tmp, *observers; + php_http_client_object_t *client_obj; + struct notify_arg arg = {NULL}; - php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return); + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return); - client_obj = zend_object_store_get_object(getThis() TSRMLS_CC); - observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); ++ client_obj = PHP_HTTP_OBJ(NULL, getThis()); + observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp); if (Z_TYPE_P(observers) != IS_OBJECT) { php_http_throw(unexpected_val, "Observer storage is corrupted", NULL); return; } - ZVAL_COPY(&args[0], getThis()); - if (request) { - ZVAL_COPY(&args[1], request); - } else { - ZVAL_UNDEF(&args[1]); - } - if (zprogress) { - ZVAL_COPY(&args[2], zprogress); - } else { - ZVAL_UNDEF(&args[2]); - } + if (client_obj->update) { + arg.cb = client_obj->update; - - Z_ADDREF_P(getThis()); - arg.args[0] = &getThis(); ++ ZVAL_COPY(&arg.args[0], getThis()); + arg.argc = 1; - spl_iterator_apply(observers, notify, args); + if (request) { - Z_ADDREF_P(request); - arg.args[1] = &request; ++ ZVAL_COPY(&arg.args[1], request); + arg.argc += 1; + } - + if (zprogress) { - Z_ADDREF_P(zprogress); - arg.args[2] = &zprogress; ++ ZVAL_COPY(&arg.args[2], zprogress); + arg.argc += 1; + } - zval_ptr_dtor(getThis()); - if (request) { - zval_ptr_dtor(request); - } - if (zprogress) { - zval_ptr_dtor(zprogress); - spl_iterator_apply(observers, notify, &arg TSRMLS_CC); ++ spl_iterator_apply(observers, notify, &arg); + - zval_ptr_dtor(&getThis()); ++ zval_ptr_dtor(getThis()); + if (request) { - zval_ptr_dtor(&request); ++ zval_ptr_dtor(request); + } + if (zprogress) { - zval_ptr_dtor(&zprogress); ++ zval_ptr_dtor(zprogress); + } } - RETVAL_ZVAL(getThis(), 1, 0); + RETVAL_ZVAL_FAST(getThis()); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1) @@@ -900,22 -952,29 +917,28 @@@ ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, attach) { - zval *observers, *observer, *retval = NULL; + zval observers_tmp, *observers, *observer, retval; + php_http_client_object_t *client_obj; - php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return); + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return); - client_obj = zend_object_store_get_object(getThis() TSRMLS_CC); - observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); ++ client_obj = PHP_HTTP_OBJ(NULL, getThis()); + observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp); if (Z_TYPE_P(observers) != IS_OBJECT) { php_http_throw(unexpected_val, "Observer storage is corrupted", NULL); return; } + if (!client_obj->update) { - client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update") TSRMLS_CC); ++ client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update")); + } + - zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer); - if (retval) { - zval_ptr_dtor(&retval); - } + ZVAL_UNDEF(&retval); + zend_call_method_with_1_params(observers, NULL, NULL, "attach", &retval, observer); + zval_ptr_dtor(&retval); - RETVAL_ZVAL(getThis(), 1, 0); + RETVAL_ZVAL_FAST(getThis()); } ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1) diff --cc php_http_client.h index 5067f6c,b536753..41671b9 --- a/php_http_client.h +++ b/php_http_client.h @@@ -85,7 -84,7 +85,7 @@@ typedef struct php_http_client_progress unsigned finished:1; } php_http_client_progress_state_t; - typedef ZEND_RESULT_CODE (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response); -typedef STATUS (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **response); ++typedef ZEND_RESULT_CODE (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **response); typedef void (*php_http_client_progress_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state); typedef struct php_http_client { @@@ -111,12 -114,15 +111,14 @@@ PHP_HTTP_API zend_class_entry *php_http_client_class_entry; typedef struct php_http_client_object { - zend_object zo; - zend_object_value zv; php_http_client_t *client; - long iterator; + php_http_object_method_t *update; + php_http_object_method_t notify; + long iterator; + zend_object zo; } php_http_client_object_t; -PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); +PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg); PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to); PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h); PHP_HTTP_API void php_http_client_free(php_http_client_t **h); diff --cc php_http_client_curl.c index fc06b38,3b4d5b1..05db912 --- a/php_http_client_curl.c +++ b/php_http_client_curl.c @@@ -334,143 -300,118 +299,142 @@@ static int php_http_curle_raw_callback( return 0; } - static int php_http_curle_dummy_callback(char *data, size_t n, size_t l, void *s) + static int php_http_curle_header_callback(char *data, size_t n, size_t l, void *arg) { - return n*l; + php_http_client_curl_handler_t *h = arg; + + return php_http_buffer_append(&h->response.headers, data, n * l); + } + + static int php_http_curle_body_callback(char *data, size_t n, size_t l, void *arg) + { + php_http_client_curl_handler_t *h = arg; + + return php_http_message_body_append(h->response.body, data, n*l); } -static STATUS php_http_curle_get_info(CURL *ch, HashTable *info) +static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) { - char *c; - long l; - double d; - struct curl_slist *s, *p; - zval *subarray, array; - INIT_PZVAL_ARRAY(&array, info); + char *c = NULL; + long l = 0; + double d = 0; + struct curl_slist *s = NULL, *p = NULL; + zval tmp = {{0}}; /* BEGIN::CURLINFO */ if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) { - add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1); + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "effective_url", lenof("effective_url"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) { - add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "response_code", lenof("response_code"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) { - add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "total_time", lenof("total_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) { - add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "namelookup_time", lenof("namelookup_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) { - add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "connect_time", lenof("connect_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) { - add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "pretransfer_time", lenof("pretransfer_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) { - add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "size_upload", lenof("size_upload"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "size_download", lenof("size_download"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "speed_download", lenof("speed_download"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) { - add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "speed_upload", lenof("speed_upload"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) { - add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "header_size", lenof("header_size"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) { - add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "request_size", lenof("request_size"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) { - add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "ssl_verifyresult", lenof("ssl_verifyresult"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) { - add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "filetime", lenof("filetime"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "content_length_download", lenof("content_length_download"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) { - add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "content_length_upload", lenof("content_length_upload"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) { - add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "starttransfer_time", lenof("starttransfer_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) { - add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1); + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "content_type", lenof("content_type"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) { - add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "redirect_time", lenof("redirect_time"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) { - add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "redirect_count", lenof("redirect_count"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) { - add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "connect_code", lenof("connect_code"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) { - add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "httpauth_avail", lenof("httpauth_avail"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) { - add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "proxyauth_avail", lenof("proxyauth_avail"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) { - add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "os_errno", lenof("os_errno"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) { - add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "num_connects", lenof("num_connects"), &tmp); } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) { - MAKE_STD_ZVAL(subarray); - array_init(subarray); + array_init(&tmp); for (p = s; p; p = p->next) { if (p->data) { - add_next_index_string(subarray, p->data, 1); + add_next_index_string(&tmp, p->data); } } - add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray); + zend_hash_str_update(info, "ssl_engines", lenof("ssl_engines"), &tmp); curl_slist_free_all(s); } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_COOKIELIST, &s)) { - array_init(&tmp); - for (p = s; p; p = p->next) { - if (p->data) { - add_next_index_string(&tmp, p->data); - } - } - zend_hash_str_update(info, "cookies", lenof("cookies"), &tmp); - curl_slist_free_all(s); - } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) { - add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1); + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "redirect_url", lenof("redirect_url"), &tmp); } #if PHP_HTTP_CURL_VERSION(7,19,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) { @@@ -639,6 -576,50 +603,54 @@@ static int compare_queue(php_http_clien return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle; } + static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_handler_t *h TSRMLS_DC) + { + php_http_message_t *response; + php_http_header_parser_t parser; + zval *zh; + + response = php_http_message_init(NULL, 0, h->response.body TSRMLS_CC); + php_http_header_parser_init(&parser TSRMLS_CC); + php_http_header_parser_parse(&parser, &h->response.headers, PHP_HTTP_HEADER_PARSER_CLEANUP, &response->hdrs, (php_http_info_callback_t) php_http_message_info_callback, (void *) &response); + php_http_header_parser_dtor(&parser); + + /* move body to right message */ + if (response->body != h->response.body) { + php_http_message_t *ptr = response; + + while (ptr->parent) { + ptr = ptr->parent; + } + response->body = ptr->body; + ptr->body = NULL; + } + php_http_message_body_addref(h->response.body); + + /* let's update the response headers */ - if ((zh = php_http_message_header(response, ZEND_STRL("Content-Length"), 1))) { - zend_hash_update(&response->hdrs, "X-Original-Content-Length", sizeof("X-Original-Content-Length"), &zh, sizeof(zval *), NULL); ++ if ((zh = php_http_message_header(response, ZEND_STRL("Content-Length")))) { ++ Z_TRY_ADDREF_P(zh); ++ zend_hash_str_update(&response->hdrs, "X-Original-Content-Length", lenof("X-Original-Content-Length"), zh); + } - if ((zh = php_http_message_header(response, ZEND_STRL("Transfer-Encoding"), 0))) { - zend_hash_update(&response->hdrs, "X-Original-Transfer-Encoding", sizeof("X-Original-Transfer-Encoding"), (void *) &zh, sizeof(zval *), NULL); - zend_hash_del(&response->hdrs, "Transfer-Encoding", sizeof("Transfer-Encoding")); ++ if ((zh = php_http_message_header(response, ZEND_STRL("Transfer-Encoding")))) { ++ Z_TRY_ADDREF_P(zh); ++ zend_hash_str_update(&response->hdrs, "X-Original-Transfer-Encoding", lenof("X-Original-Transfer-Encoding"), zh); ++ zend_hash_str_del(&response->hdrs, "Transfer-Encoding", lenof("Transfer-Encoding")); + } - if ((zh = php_http_message_header(response, ZEND_STRL("Content-Range"), 0))) { - zend_hash_update(&response->hdrs, "X-Original-Content-Range", sizeof("X-Original-Content-Range"), &zh, sizeof(zval *), NULL); - zend_hash_del(&response->hdrs, "Content-Range", sizeof("Content-Range")); ++ if ((zh = php_http_message_header(response, ZEND_STRL("Content-Range")))) { ++ Z_TRY_ADDREF_P(zh); ++ zend_hash_str_update(&response->hdrs, "X-Original-Content-Range", lenof("X-Original-Content-Range"), zh); ++ zend_hash_str_del(&response->hdrs, "Content-Range", lenof("Content-Range")); + } - if ((zh = php_http_message_header(response, ZEND_STRL("Content-Encoding"), 0))) { - zend_hash_update(&response->hdrs, "X-Original-Content-Encoding", sizeof("X-Original-Content-Encoding"), &zh, sizeof(zval *), NULL); - zend_hash_del(&response->hdrs, "Content-Encoding", sizeof("Content-Encoding")); ++ if ((zh = php_http_message_header(response, ZEND_STRL("Content-Encoding")))) { ++ Z_TRY_ADDREF_P(zh); ++ zend_hash_str_update(&response->hdrs, "X-Original-Content-Encoding", lenof("X-Original-Content-Encoding"), zh); ++ zend_hash_str_del(&response->hdrs, "Content-Encoding", lenof("Content-Encoding")); + } + php_http_message_update_headers(response); + + return response; + } + static void php_http_curlm_responsehandler(php_http_client_t *context) { int remaining = 0; @@@ -941,12 -929,13 +957,13 @@@ static ZEND_RESULT_CODE php_http_curle_ return SUCCESS; } -static STATUS php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) +static ZEND_RESULT_CODE php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; - if (Z_TYPE_P(val) == IS_TRUE) { - curl->options.headers = curl_slist_append(curl->options.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5"); - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ACCEPT_ENCODING, Z_BVAL_P(val) ? "" : NULL)) { ++ if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ACCEPT_ENCODING, Z_TYPE_P(val) == IS_TRUE ? "" : NULL)) { + return FAILURE; } return SUCCESS; } @@@ -1079,8 -1081,45 +1096,44 @@@ static ZEND_RESULT_CODE php_http_curle_ return SUCCESS; } + #if PHP_HTTP_CURL_VERSION(7,37,0) -static STATUS php_http_curle_option_set_proxyheader(php_http_option_t *opt, zval *val, void *userdata) ++static ZEND_RESULT_CODE php_http_curle_option_set_proxyheader(php_http_option_t *opt, zval *val, void *userdata) + { + php_http_client_curl_handler_t *curl = userdata; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { - php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0); - zval **header_val, *header_cpy; - HashPosition pos; ++ php_http_arrkey_t header_key; ++ zval *header_val; + php_http_buffer_t header; + + php_http_buffer_init(&header); - FOREACH_KEYVAL(pos, val, header_key, header_val) { - if (header_key.type == HASH_KEY_IS_STRING) { - header_cpy = php_http_ztyp(IS_STRING, *header_val); - php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy)); ++ ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(val), header_key.h, header_key.key, header_val) ++ { ++ if (header_key.key) { ++ zend_string *zs = zval_get_string(header_val); ++ php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, zs->val); + php_http_buffer_fix(&header); + curl->options.proxyheaders = curl_slist_append(curl->options.proxyheaders, header.data); + php_http_buffer_reset(&header); - - zval_ptr_dtor(&header_cpy); ++ zend_string_release(zs); + } + } ++ ZEND_HASH_FOREACH_END(); + php_http_buffer_dtor(&header); + } + if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, curl->options.proxyheaders)) { + return FAILURE; + } + if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE)) { + curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, NULL); + return FAILURE; + } + return SUCCESS; + } + #endif + #if PHP_HTTP_CURL_VERSION(7,21,3) -static STATUS php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata) +static ZEND_RESULT_CODE php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; @@@ -1109,7 -1148,31 +1162,31 @@@ } #endif -#if PHP_HTTP_CURL_VERSION(7,21,4) -static STATUS php_http_curle_option_set_ssl_tlsauthtype(php_http_option_t *opt, zval *val, void *userdata) ++#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP) ++static ZEND_RESULT_CODE php_http_curle_option_set_ssl_tlsauthtype(php_http_option_t *opt, zval *val, void *userdata) + { + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (val && Z_LVAL_P(val)) { + switch (Z_LVAL_P(val)) { + case CURL_TLSAUTH_SRP: + if (CURLE_OK == curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_CURL_TLSAUTH_SRP)) { + return SUCCESS; + } + /* no break */ + default: + return FAILURE; + } + } + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_CURL_TLSAUTH_DEF)) { + return FAILURE; + } + return SUCCESS; + } + #endif + -static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) +static void php_http_curle_options_init(php_http_options_t *registry) { php_http_option_t *opt; @@@ -1374,15 -1454,32 +1467,32 @@@ # endif #endif #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL) - php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL); #endif #if PHP_HTTP_CURL_VERSION(7,36,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, IS_BOOL))) { + if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } - if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, IS_BOOL))) { + if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } + #endif + #if PHP_HTTP_CURL_VERSION(7,39,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("pinned_publickey"), CURLOPT_PINNEDPUBLICKEY, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + #endif -#if PHP_HTTP_CURL_VERSION(7,21,4) ++#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP) + if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthtype"), CURLOPT_TLSAUTH_TYPE, IS_LONG))) { + opt->setter = php_http_curle_option_set_ssl_tlsauthtype; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthuser"), CURLOPT_TLSAUTH_USERNAME, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthpass"), CURLOPT_TLSAUTH_PASSWORD, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } #endif } } @@@ -1393,8 -1490,8 +1503,9 @@@ static zval *php_http_curle_get_option( zval *option; if ((option = php_http_option_get(opt, options, NULL))) { - option = php_http_ztyp(opt->type, option); - zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL); ++ Z_TRY_ADDREF_P(option); + convert_to_explicit_type_ex(option, opt->type); + zend_hash_update(&curl->options.cache, opt->name, option); } return option; } @@@ -1551,12 -1650,8 +1666,8 @@@ static php_http_client_curl_handler_t * handler->rf = rf; handler->client = h; handler->handle = handle; - handler->request.buffer = php_http_buffer_init(NULL); - handler->request.parser = php_http_message_parser_init(NULL); - handler->request.message = php_http_message_init(NULL, 0, NULL); - handler->response.buffer = php_http_buffer_init(NULL); - handler->response.parser = php_http_message_parser_init(NULL); - handler->response.message = php_http_message_init(NULL, 0, NULL); - handler->response.body = php_http_message_body_init(NULL, NULL TSRMLS_CC); ++ handler->response.body = php_http_message_body_init(NULL, NULL); + php_http_buffer_init(&handler->response.headers); php_http_buffer_init(&handler->options.cookies); php_http_buffer_init(&handler->options.ranges); zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0); @@@ -1709,17 -1809,15 +1823,13 @@@ static void php_http_client_curl_handle static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler) { - TSRMLS_FETCH_FROM_CTX(handler->client->ts); - php_http_client_curl_handler_clear(handler); - php_resource_factory_handle_dtor(handler->rf, handler->handle TSRMLS_CC); + php_resource_factory_handle_dtor(handler->rf, handler->handle); php_resource_factory_free(&handler->rf); - php_http_message_parser_free(&handler->request.parser); - php_http_message_free(&handler->request.message); - php_http_buffer_free(&handler->request.buffer); - php_http_message_parser_free(&handler->response.parser); - php_http_message_free(&handler->response.message); - php_http_buffer_free(&handler->response.buffer); + php_http_message_body_free(&handler->response.body); + php_http_buffer_dtor(&handler->response.headers); php_http_buffer_dtor(&handler->options.ranges); php_http_buffer_dtor(&handler->options.cookies); zend_hash_destroy(&handler->options.cache); @@@ -2095,21 -2196,19 +2205,20 @@@ php_http_client_ops_t *php_http_client_ PHP_MINIT_FUNCTION(http_client_curl) { php_http_options_t *options; - php_http_client_driver_t driver; - php_http_client_driver_t driver = { - ZEND_STRL("curl"), - &php_http_client_curl_ops - }; - if (SUCCESS != php_http_client_driver_add(&driver)) { - return FAILURE; - } + PHP_HTTP_G->client.curl.driver.driver_name = zend_string_init(ZEND_STRL("curl"), 1); + PHP_HTTP_G->client.curl.driver.client_name = zend_string_init(ZEND_STRL("http\\Client\\Curl"), 1); + PHP_HTTP_G->client.curl.driver.request_name = zend_string_init(ZEND_STRL("http\\Client\\Curl\\Request"), 1); + PHP_HTTP_G->client.curl.driver.client_ops = &php_http_client_curl_ops; + + if (SUCCESS != php_http_client_driver_add(&PHP_HTTP_G->client.curl.driver)) { + return FAILURE; + } - if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl"), &php_http_curlm_resource_factory_ops, NULL, NULL TSRMLS_CC)) { + if (SUCCESS != php_persistent_handle_provide(PHP_HTTP_G->client.curl.driver.client_name, &php_http_curlm_resource_factory_ops, NULL, NULL)) { return FAILURE; } - if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl\\Request"), &php_http_curle_resource_factory_ops, NULL, NULL TSRMLS_CC)) { + if (SUCCESS != php_persistent_handle_provide(PHP_HTTP_G->client.curl.driver.request_name, &php_http_curle_resource_factory_ops, NULL, NULL)) { return FAILURE; } diff --cc php_http_cookie.c index 706fc10,354dfa6..ff67b1c --- a/php_http_cookie.c +++ b/php_http_cookie.c @@@ -378,14 -372,9 +378,14 @@@ php_http_cookie_object_t *php_http_cook { php_http_cookie_object_t *o; - o = ecalloc(sizeof(*o), 1); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); + if (!ce) { + ce = php_http_cookie_class_entry; + } + - o = ecalloc(sizeof(*o) + sizeof(zval) * (ce->default_properties_count - 1), 1); ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); + o->zo.handlers = &php_http_cookie_object_handlers; if (list) { o->list = list; diff --cc php_http_encoding.c index 1ef355e,b7050f6..ffa10b3 --- a/php_http_encoding.c +++ b/php_http_encoding.c @@@ -909,9 -923,13 +909,9 @@@ php_http_encoding_stream_object_t *php_ { php_http_encoding_stream_object_t *o; - o = ecalloc(1, sizeof(*o) + (ce->default_properties_count - 1) * sizeof(zval)); - o = ecalloc(1, sizeof(*o)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (ptr) { - *ptr = o; - } ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); if (s) { o->stream = s; diff --cc php_http_env_response.c index 80043a2,a4431b6..7c76c08 --- a/php_http_env_response.c +++ b/php_http_env_response.c @@@ -837,19 -887,31 +838,27 @@@ typedef struct php_http_env_response_st unsigned started:1; unsigned finished:1; + unsigned chunked:1; } php_http_env_response_stream_ctx_t; -static STATUS php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg) +static ZEND_RESULT_CODE php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg) { php_http_env_response_stream_ctx_t *ctx; - TSRMLS_FETCH_FROM_CTX(r->ts); ctx = ecalloc(1, sizeof(*ctx)); ctx->stream = init_arg; - if (SUCCESS != zend_list_addref(ctx->stream->rsrc_id)) { - efree(ctx); - return FAILURE; - } - zend_hash_init(&ctx->header, 0, NULL, ZVAL_PTR_DTOR, 0); - php_http_version_init(&ctx->version, 1, 1 TSRMLS_CC); + ++GC_REFCOUNT(ctx->stream->res); + ZEND_INIT_SYMTABLE(&ctx->header); + php_http_version_init(&ctx->version, 1, 1); ctx->status_code = 200; + ctx->chunked = 1; - ctx->request = get_request(r->options TSRMLS_CC); ++ ctx->request = get_request(&r->options); + + /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */ + if (ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0) { + ctx->version.minor = 0; + } r->ctx = ctx; @@@ -864,34 -927,56 +873,58 @@@ static void php_http_env_response_strea efree(ctx); r->ctx = NULL; } -static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t *ctx, HashTable *header TSRMLS_DC) +static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t *ctx, HashTable *header) { - HashPosition pos; - zval **val; + zval *val; - FOREACH_HASH_VAL(pos, header, val) { - if (Z_TYPE_PP(val) == IS_ARRAY) { - php_http_env_response_stream_header(ctx, Z_ARRVAL_PP(val) TSRMLS_CC); + ZEND_HASH_FOREACH_VAL(header, val) + { + if (Z_TYPE_P(val) == IS_ARRAY) { + php_http_env_response_stream_header(ctx, Z_ARRVAL_P(val)); } else { - zval *tmp = php_http_ztyp(IS_STRING, *val); + zend_string *zs = zval_get_string(val); + if (ctx->chunked) { + /* disable chunked transfer encoding if we've got an explicit content-length */ - if (!strncasecmp(Z_STRVAL_P(tmp), "Content-Length:", lenof("Content-Length:"))) { ++ if (!strncasecmp(zs->val, "Content-Length:", lenof("Content-Length:"))) { + ctx->chunked = 0; + } + } - php_stream_write(ctx->stream, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + php_stream_write(ctx->stream, zs->val, zs->len); php_stream_write_string(ctx->stream, PHP_HTTP_CRLF); - zval_ptr_dtor(&tmp); + zend_string_release(zs); } } + ZEND_HASH_FOREACH_END(); } -static STATUS php_http_env_response_stream_start(php_http_env_response_stream_ctx_t *ctx TSRMLS_DC) +static ZEND_RESULT_CODE php_http_env_response_stream_start(php_http_env_response_stream_ctx_t *ctx) { if (ctx->started || ctx->finished) { return FAILURE; } -- php_stream_printf(ctx->stream TSRMLS_CC, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code)); ++ php_stream_printf(ctx->stream, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code)); + + /* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */ + if (ctx->version.major == 1 && ctx->version.minor == 0) { + ctx->chunked = 0; + } else if (ctx->status_code == 204 || ctx->status_code/100 == 1) { + ctx->chunked = 0; + } else if (ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT")) { + ctx->chunked = 0; + } + - php_http_env_response_stream_header(ctx, &ctx->header TSRMLS_CC); + php_http_env_response_stream_header(ctx, &ctx->header); + + /* enable chunked transfer encoding */ + if (ctx->chunked) { + php_stream_write_string(ctx->stream, "Transfer-Encoding: chunked" PHP_HTTP_CRLF); + } ++ php_stream_write_string(ctx->stream, PHP_HTTP_CRLF); + ctx->started = 1; + return SUCCESS; } static long php_http_env_response_stream_get_status(php_http_env_response_t *r) @@@ -1010,11 -1101,16 +1047,15 @@@ static ZEND_RESULT_CODE php_http_env_re return FAILURE; } + if (stream_ctx->chunked && 2 != php_stream_write_string(stream_ctx->stream, PHP_HTTP_CRLF)) { + return FAILURE; + } + return SUCCESS; } -static STATUS php_http_env_response_stream_flush(php_http_env_response_t *r) +static ZEND_RESULT_CODE php_http_env_response_stream_flush(php_http_env_response_t *r) { php_http_env_response_stream_ctx_t *stream_ctx = r->ctx; - TSRMLS_FETCH_FROM_CTX(r->ts); if (stream_ctx->finished) { return FAILURE; diff --cc php_http_info.c index f0fe7ad,9050919..66007bf --- a/php_http_info.c +++ b/php_http_info.c @@@ -71,9 -71,9 +71,9 @@@ php_http_info_t *php_http_info_parse(ph info = php_http_info_init(info TSRMLS_CC); - /* and nothing than SPACE or NUL after HTTP/1.x */ + /* and nothing than SPACE or NUL after HTTP/X.x */ - if (!php_http_version_parse(&info->http.version, http TSRMLS_CC) + if (!php_http_version_parse(&info->http.version, http) - || (http[lenof("HTTP/1.1")] && (!PHP_HTTP_IS_CTYPE(space, http[lenof("HTTP/1.1")])))) { + || (http[lenof("HTTP/X.x")] && (!PHP_HTTP_IS_CTYPE(space, http[lenof("HTTP/X.x")])))) { if (free_info) { php_http_info_free(&info); } @@@ -116,11 -125,20 +125,20 @@@ info->type = PHP_HTTP_REQUEST; if (url && http > url) { - PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url - pre_header); + size_t url_len = url - pre_header; + + PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url_len); + while (' ' == *url) ++url; while (' ' == *(http-1)) --http; + if (http > url) { - PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, ~0); + /* CONNECT presents an authority only */ + if (strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT")) { - PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, ~0 TSRMLS_CC); ++ PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, ~0); + } else { - PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, ~0 TSRMLS_CC); ++ PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, ~0); + } } else { PTR_SET(PHP_HTTP_INFO(info).request.method, NULL); return NULL; diff --cc php_http_message.c index 1456950,5a278f6..ae7ca6e --- a/php_http_message.c +++ b/php_http_message.c @@@ -586,38 -616,28 +586,37 @@@ static void php_http_message_object_pro char *version_str; size_t version_len; - php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL TSRMLS_CC); - RETVAL_STRINGL(version_str, version_len, 0); + php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL); + RETVAL_STR(php_http_cs2zs(version_str, version_len)); } -static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value TSRMLS_DC) { - zval *cpy = php_http_ztyp(IS_STRING, value); - php_http_version_parse(&obj->message->http.version, Z_STRVAL_P(cpy) TSRMLS_CC); - zval_ptr_dtor(&cpy); +static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value) { + zend_string *zs = zval_get_string(value); + php_http_version_parse(&obj->message->http.version, zs->val); + zend_string_release(zs); } -static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { +static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value ) { array_init(return_value); - zend_hash_copy(Z_ARRVAL_P(return_value), &obj->message->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value)); } -static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value TSRMLS_DC) { - zval *cpy = php_http_ztyp(IS_ARRAY, value); +static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value) { + HashTable *headers; + zval *orig_value = value; + + if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) { + convert_to_array_ex(value); - } else { - headers = HASH_OF(value); + } ++ headers = HASH_OF(value); zend_hash_clean(&obj->message->hdrs); - zend_hash_copy(&obj->message->hdrs, Z_ARRVAL_P(cpy), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); - zval_ptr_dtor(&cpy); + array_copy(headers, &obj->message->hdrs); + + if (orig_value != value) { + zval_ptr_dtor(value); + } } -static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { +static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value) { if (obj->body) { - RETVAL_OBJVAL(obj->body->zv, 1); + RETVAL_OBJECT(&obj->body->zo, 1); } else { RETVAL_NULL(); } @@@ -798,9 -832,13 +797,9 @@@ php_http_message_object_t *php_http_mes { php_http_message_object_t *o; - o = ecalloc(1, sizeof(php_http_message_object_t) + (ce->default_properties_count - 1) * sizeof(zval)); - o = ecalloc(1, sizeof(php_http_message_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (ptr) { - *ptr = o; - } ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); if (msg) { o->message = msg; @@@ -1105,20 -1157,26 +1104,23 @@@ static PHP_METHOD(HttpMessage, getHeade PHP_HTTP_MESSAGE_OBJECT_INIT(obj); - if ((header = php_http_message_header(obj->message, header_str, header_len, 0))) { + if ((header = php_http_message_header(obj->message, header_str, header_len))) { if (!header_ce) { RETURN_ZVAL(header, 1, 1); - } else if (instanceof_function(header_ce, php_http_header_class_entry TSRMLS_CC)) { + } else if (instanceof_function(header_ce, php_http_header_class_entry)) { + php_http_object_method_t cb; - zval *header_name, **argv[2]; + zval argv[2]; - MAKE_STD_ZVAL(header_name); - ZVAL_STRINGL(header_name, header_str, header_len, 1); - - argv[0] = &header_name; - argv[1] = &header; + ZVAL_STRINGL(&argv[0], header_str, header_len); + ZVAL_COPY(&argv[1], header); object_init_ex(return_value, header_ce); - php_http_method_call(return_value, ZEND_STRL("__construct"), 2, argv, NULL); - php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct") TSRMLS_CC); - php_http_object_method_call(&cb, return_value, NULL, 2, argv TSRMLS_CC); ++ php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct")); ++ php_http_object_method_call(&cb, return_value, NULL, 2, argv); + php_http_object_method_dtor(&cb); - zval_ptr_dtor(&header_name); - zval_ptr_dtor(&header); + zval_ptr_dtor(&argv[0]); + zval_ptr_dtor(&argv[1]); return; } else { diff --cc php_http_message_body.c index 6c677bd,84e84e4..1c540c7 --- a/php_http_message_body.c +++ b/php_http_message_body.c @@@ -554,9 -573,13 +554,9 @@@ php_http_message_body_object_t *php_htt { php_http_message_body_object_t *o; - o = ecalloc(1, sizeof(php_http_message_body_object_t) + (ce->default_properties_count - 1) * sizeof(zval)); - o = ecalloc(1, sizeof(php_http_message_body_object_t)); - zend_object_std_init((zend_object *) o, php_http_message_body_class_entry TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (ptr) { - *ptr = o; - } ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, php_http_message_body_class_entry); + object_properties_init(&o->zo, ce); if (body) { o->body = body; diff --cc php_http_message_parser.c index 440a5f3,57805ec..e40e7b3 --- a/php_http_message_parser.c +++ b/php_http_message_parser.c @@@ -517,9 -525,13 +517,9 @@@ php_http_message_parser_object_t *php_h { php_http_message_parser_object_t *o; - o = ecalloc(1, sizeof(php_http_message_parser_object_t) + (ce->default_properties_count - 1) * sizeof(zval)); - o = ecalloc(1, sizeof(php_http_message_parser_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (ptr) { - *ptr = o; - } ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); if (parser) { o->parser = parser; diff --cc php_http_object.c index 9024ee9,7d902ea..e42998e --- a/php_http_object.c +++ b/php_http_object.c @@@ -23,25 -21,23 +23,24 @@@ php_http_object_t *php_http_object_new_ { php_http_object_t *o; - o = ecalloc(1, sizeof(php_http_object_t) + (ce->default_properties_count - 1) * sizeof(zval)); - o = ecalloc(1, sizeof(php_http_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); ++ o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); - if (ptr) { - *ptr = o; - } + o->intern = intern; + o->zo.handlers = &php_http_object_handlers; - o->zv.handle = zend_objects_store_put(o, NULL, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC); - o->zv.handlers = zend_get_std_object_handlers(); + return o; +} - return o->zv; +void php_http_object_free(zend_object *object) +{ - php_http_object_t *obj = PHP_HTTP_OBJ(object, NULL); + zend_object_std_dtor(object); } -STATUS php_http_new(zend_object_value *ovp, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC) +ZEND_RESULT_CODE php_http_new(void **obj_ptr, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr) { - zend_object_value ov; + void *obj; if (!ce) { ce = parent_ce; @@@ -57,29 -53,71 +56,64 @@@ return SUCCESS; } - ZEND_RESULT_CODE php_http_method_call(zval *object, const char *method_str, size_t method_len, int argc, zval argv[], zval *retval_ptr) -php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len TSRMLS_DC) ++php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len) + { - zval *zfn; - + if (!cb) { + cb = ecalloc(1, sizeof(*cb)); + } else { + memset(cb, 0, sizeof(*cb)); + } + - MAKE_STD_ZVAL(zfn); - ZVAL_STRINGL(zfn, method_str, method_len, 1); - + cb->fci.size = sizeof(cb->fci); - cb->fci.function_name = zfn; ++ ZVAL_STRINGL(&cb->fci.function_name, method_str, method_len); + cb->fcc.initialized = 1; + cb->fcc.calling_scope = cb->fcc.called_scope = Z_OBJCE_P(zobject); - cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&zobject, Z_STRVAL_P(cb->fci.function_name), Z_STRLEN_P(cb->fci.function_name), NULL TSRMLS_CC); ++ cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL); + + return cb; + } + + void php_http_object_method_dtor(php_http_object_method_t *cb) + { - if (cb->fci.function_name) { - zval_ptr_dtor(&cb->fci.function_name); - cb->fci.function_name = NULL; - } ++ zval_ptr_dtor(&cb->fci.function_name); + } + + void php_http_object_method_free(php_http_object_method_t **cb) + { + if (*cb) { + php_http_object_method_dtor(*cb); + efree(*cb); + *cb = NULL; + } + } + -STATUS php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval **retval_ptr, int argc, zval ***args TSRMLS_DC) ++ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval_ptr, int argc, zval *args) { - zend_fcall_info fci; - zval retval; - STATUS rv; - zval *retval = NULL; + ZEND_RESULT_CODE rv; ++ zval retval; + ZVAL_UNDEF(&retval); - fci.size = sizeof(fci); - fci.object = Z_OBJ_P(object); - fci.retval = retval_ptr ? retval_ptr : &retval; - fci.param_count = argc; - fci.params = argv; - fci.no_separation = 1; - fci.symbol_table = NULL; - fci.function_table = NULL; - - ZVAL_STRINGL(&fci.function_name, method_str, method_len); - rv = zend_call_function(&fci, NULL TSRMLS_CC); - zval_ptr_dtor(&fci.function_name); - - if (!retval_ptr) { + Z_ADDREF_P(zobject); - cb->fci.object_ptr = zobject; - cb->fcc.object_ptr = zobject; ++ cb->fci.object = Z_OBJ_P(zobject); ++ cb->fcc.object = Z_OBJ_P(zobject); + - cb->fci.retval_ptr_ptr = retval_ptr ? retval_ptr : &retval; ++ cb->fci.retval = retval_ptr ? retval_ptr : &retval; + + cb->fci.param_count = argc; + cb->fci.params = args; + + if (cb->fcc.called_scope != Z_OBJCE_P(zobject)) { + cb->fcc.called_scope = Z_OBJCE_P(zobject); - cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&zobject, Z_STRVAL_P(cb->fci.function_name), Z_STRLEN_P(cb->fci.function_name), NULL TSRMLS_CC); ++ cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL); + } + - rv = zend_call_function(&cb->fci, &cb->fcc TSRMLS_CC); ++ rv = zend_call_function(&cb->fci, &cb->fcc); + - zval_ptr_dtor(&zobject); - if (!retval_ptr && retval) { ++ zval_ptr_dtor(zobject); ++ if (!retval_ptr && !Z_ISUNDEF(retval)) { zval_ptr_dtor(&retval); } + return rv; } diff --cc php_http_object.h index 24e5a18,1fbd817..c6bd17f --- a/php_http_object.h +++ b/php_http_object.h @@@ -14,20 -14,27 +14,29 @@@ #define PHP_HTTP_OBJECT_H typedef struct php_http_object { + void *intern; zend_object zo; - zend_object_value zv; } php_http_object_t; -zend_object_value php_http_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, php_http_object_t **ptr TSRMLS_DC); +zend_object *php_http_object_new(zend_class_entry *ce TSRMLS_DC); +php_http_object_t *php_http_object_new_ex(zend_class_entry *ce, void *nothing); -typedef zend_object_value (*php_http_new_t)(zend_class_entry *ce, void *, void ** TSRMLS_DC); +typedef void *(*php_http_new_t)(zend_class_entry *ce, void *); -STATUS php_http_new(zend_object_value *ov, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC); +ZEND_RESULT_CODE php_http_new(void **obj_ptr, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr); - ZEND_RESULT_CODE php_http_method_call(zval *object, const char *method_str, size_t method_len, int argc, zval argv[], zval *retval_ptr); + +PHP_MINIT_FUNCTION(http_object); + typedef struct php_http_method { + zend_fcall_info fci; + zend_fcall_info_cache fcc; + } php_http_object_method_t; + -php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len TSRMLS_DC); -STATUS php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval **retval, int argc, zval ***args TSRMLS_DC); ++php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len); ++ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval, int argc, zval *args); + void php_http_object_method_dtor(php_http_object_method_t *cb); + void php_http_object_method_free(php_http_object_method_t **cb); + #endif diff --cc php_http_url.c index c4c0e15,5316265..048bbee --- a/php_http_url.c +++ b/php_http_url.c @@@ -57,9 -57,9 +57,9 @@@ static inline char *localhostname(void return estrndup("localhost", lenof("localhost")); } - #define url(buf) ((php_http_url_t *) buf.data) + #define url(buf) ((php_http_url_t *) (buf).data) -static php_http_url_t *php_http_url_from_env(TSRMLS_D) +static php_http_url_t *php_http_url_from_env(void) { zval *https, *zhost, *zport; long port; @@@ -123,8 -123,39 +123,25 @@@ return url(buf); } -void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC) -{ - php_http_url_t *url = php_http_url_mod((const php_http_url_t *) old_url, (const php_http_url_t *) new_url, flags TSRMLS_CC); - - if (url_ptr) { - *url_ptr = php_http_url_to_php_url(url); - } - if (url_str) { - php_http_url_to_string(url, url_str, url_len, 0); - } - - php_http_url_free(&url); -} - #define url_isset(u,n) \ ((u)&&(u)->n) + #define url_append(buf, append) do { \ + char *_ptr = (buf)->data; \ + php_http_url_t *_url = (php_http_url_t *) _ptr, _mem = *_url; \ + append; \ + /* relocate */ \ + if (_ptr != (buf)->data) { \ + ptrdiff_t diff = (buf)->data - _ptr; \ + _url = (php_http_url_t *) (buf)->data; \ + if (_mem.scheme) _url->scheme += diff; \ + if (_mem.user) _url->user += diff; \ + if (_mem.pass) _url->pass += diff; \ + if (_mem.host) _url->host += diff; \ + if (_mem.path) _url->path += diff; \ + if (_mem.query) _url->query += diff; \ + if (_mem.fragment) _url->fragment += diff; \ + } \ + } while (0) #define url_copy(n) do { \ if (url_isset(new_url, n)) { \ url(buf)->n = &buf.data[buf.used]; \ @@@ -209,20 -240,20 +226,20 @@@ php_http_url_t *php_http_url_mod(const if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) { zval qarr, qstr; - INIT_PZVAL(&qstr); - INIT_PZVAL(&qarr); array_init(&qarr); - ZVAL_STRING(&qstr, old_url->query, 0); - php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC); - ZVAL_STRING(&qstr, new_url->query, 0); - php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC); + ZVAL_STRING(&qstr, old_url->query); + php_http_querystring_update(&qarr, &qstr, NULL); + zval_ptr_dtor(&qstr); + ZVAL_STRING(&qstr, new_url->query); + php_http_querystring_update(&qarr, &qstr, NULL); + zval_ptr_dtor(&qstr); ZVAL_NULL(&qstr); - php_http_querystring_update(&qarr, NULL, &qstr TSRMLS_CC); + php_http_querystring_update(&qarr, NULL, &qstr); url(buf)->query = &buf.data[buf.used]; - php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1); + url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1)); zval_dtor(&qstr); zval_dtor(&qarr); @@@ -367,9 -398,45 +384,45 @@@ char *php_http_url_to_string(const php_ return buf.data; } + char *php_http_url_authority_to_string(const php_http_url_t *url, char **url_str, size_t *url_len) + { + php_http_buffer_t buf; + + php_http_buffer_init(&buf); + + if (url->user && *url->user) { + php_http_buffer_appendl(&buf, url->user); + if (url->pass && *url->pass) { + php_http_buffer_appends(&buf, ":"); + php_http_buffer_appendl(&buf, url->pass); + } + php_http_buffer_appends(&buf, "@"); + } + + if (url->host && *url->host) { + php_http_buffer_appendl(&buf, url->host); + if (url->port) { + php_http_buffer_appendf(&buf, ":%hu", url->port); + } + } + + php_http_buffer_shrink(&buf); + php_http_buffer_fix(&buf); + + if (url_len) { + *url_len = buf.used; + } + + if (url_str) { + *url_str = buf.data; + } + + return buf.data; + } + -php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags TSRMLS_DC) +php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags) { - zval *zcpy; + zend_string *zs; php_http_url_t *purl; switch (Z_TYPE_P(value)) { @@@ -396,50 -463,52 +449,50 @@@ php_http_url_t *php_http_url_from_struc php_http_buffer_account(&buf, sizeof(php_http_url_t)); memset(buf.data, 0, buf.used); - if (SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("scheme")))) { + zend_string *zs = zval_get_string(e); url(buf)->scheme = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } - if (SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("user")))) { + zend_string *zs = zval_get_string(e); url(buf)->user = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } - if (SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("pass")))) { + zend_string *zs = zval_get_string(e); url(buf)->pass = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } - if (SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("host")))) { + zend_string *zs = zval_get_string(e); url(buf)->host = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } - if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_LONG, *e); - url(buf)->port = (unsigned short) Z_LVAL_P(cpy); - zval_ptr_dtor(&cpy); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("port")))) { + url(buf)->port = (unsigned short) zval_get_long(e); } - if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("path")))) { + zend_string *zs = zval_get_string(e); url(buf)->path = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } - if (SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("query")))) { + zend_string *zs = zval_get_string(e); url(buf)->query = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } - if (SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) { - zval *cpy = php_http_ztyp(IS_STRING, *e); + if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("fragment")))) { + zend_string *zs = zval_get_string(e); url(buf)->fragment = &buf.data[buf.used]; - php_http_buffer_append(&buf, zs->val, zs->len + 1); - url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1)); - zval_ptr_dtor(&cpy); ++ url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1)); + zend_string_release(zs); } return url(buf); @@@ -868,8 -926,10 +921,10 @@@ static ZEND_RESULT_CODE parse_hostinfo( break; default: - if (port) { + if (ptr == end) { + break; + } else if (port) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Failed to parse port; unexpected byte 0x%02x at pos %u in '%s'", (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); return FAILURE; diff --cc php_http_url.h index df35a9e,9268048..b7402e9 --- a/php_http_url.h +++ b/php_http_url.h @@@ -56,22 -57,26 +57,23 @@@ typedef struct php_http_url char *fragment; } php_http_url_t; -PHP_HTTP_API php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags TSRMLS_DC); -PHP_HTTP_API php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags TSRMLS_DC); -/* deprecated */ -PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC); -/* use this instead */ -PHP_HTTP_API php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags TSRMLS_DC); +PHP_HTTP_API php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags); ++PHP_HTTP_API php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags); +PHP_HTTP_API php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags); PHP_HTTP_API php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent); PHP_HTTP_API php_http_url_t *php_http_url_from_struct(HashTable *ht); -PHP_HTTP_API php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags TSRMLS_DC); -PHP_HTTP_API HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct TSRMLS_DC); +PHP_HTTP_API php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags); +PHP_HTTP_API HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct); PHP_HTTP_API char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent); + PHP_HTTP_API char *php_http_url_authority_to_string(const php_http_url_t *url, char **url_str, size_t *url_len); PHP_HTTP_API void php_http_url_free(php_http_url_t **url); - -PHP_HTTP_API STATUS php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len TSRMLS_DC); -PHP_HTTP_API STATUS php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len TSRMLS_DC); +PHP_HTTP_API ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len); +PHP_HTTP_API ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len); -static inline void php_http_url_argsep(const char **str, size_t *len TSRMLS_DC) +static inline void php_http_url_argsep(const char **str, size_t *len) { - if (SUCCESS != php_http_ini_entry(ZEND_STRL("arg_separator.output"), str, len, 0 TSRMLS_CC) || !*len) { + if (SUCCESS != php_http_ini_entry(ZEND_STRL("arg_separator.output"), str, len, 0) || !*len) { *str = PHP_HTTP_URL_ARGSEP; *len = lenof(PHP_HTTP_URL_ARGSEP); } diff --cc php_http_version.c index 0579467,7adef9d..5e8008d --- a/php_http_version.c +++ b/php_http_version.c @@@ -24,10 -24,10 +24,10 @@@ php_http_version_t *php_http_version_in return v; } -php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str TSRMLS_DC) +php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str) { long major, minor; - char separator = 0, *stop = NULL; + char separator = 0; register const char *ptr = str; switch (*ptr) {