X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=src%2Fphp_http_client_curl.c;h=94cdf474180549023805549a22230d02e20b3b4b;hp=fed92fc078f2c4a95649c53901f5393c8c05483a;hb=82923890d9ce44a0642ac2f5ea0cb343aaf50fe3;hpb=bdd6edb59194cda9e5fcb393c48ab4230fceb32a diff --git a/src/php_http_client_curl.c b/src/php_http_client_curl.c index fed92fc..94cdf47 100644 --- a/src/php_http_client_curl.c +++ b/src/php_http_client_curl.c @@ -12,49 +12,18 @@ #include "php_http_api.h" #include "php_http_client.h" +#include "php_http_client_curl_event.h" +#include "php_http_client_curl_user.h" -#if PHP_HTTP_HAVE_CURL - -#if PHP_HTTP_HAVE_EVENT -# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) -# include -# define event_base_new event_init -# define event_assign(e, b, s, a, cb, d) do {\ - event_set(e, s, a, cb, d); \ - event_base_set(b, e); \ - } while(0) -# else -# if PHP_HTTP_HAVE_EVENT2 -# include -# include -# else -# error "libevent presence is unknown" -# endif -# endif -# ifndef DBG_EVENTS -# define DBG_EVENTS 0 -# endif -#endif +#if PHP_HTTP_HAVE_LIBCURL -#ifdef PHP_HTTP_HAVE_OPENSSL +#if PHP_HTTP_HAVE_LIBCURL_OPENSSL # include #endif -#ifdef PHP_HTTP_HAVE_GNUTLS -# include +#if PHP_HTTP_HAVE_LIBCURL_GNUTLS +# include #endif -typedef struct php_http_client_curl { - CURLM *handle; - - int unfinished; /* int because of curl_multi_perform() */ - -#if PHP_HTTP_HAVE_EVENT - struct event_base *evbase; - struct event *timeout; - unsigned useevents:1; -#endif -} php_http_client_curl_t; - typedef struct php_http_client_curl_handler { CURL *handle; php_resource_factory_t *rf; @@ -76,15 +45,15 @@ typedef struct php_http_client_curl_handler { php_http_buffer_t cookies; php_http_buffer_t ranges; - long redirects; - unsigned range_request:1; - unsigned encode_cookies:1; - struct { - uint count; + uint32_t count; double delay; } retry; + long redirects; + unsigned range_request:1; + unsigned encode_cookies:1; + } options; } php_http_client_curl_handler_t; @@ -110,7 +79,7 @@ static inline php_http_curle_storage_t *php_http_curle_get_storage(CURL *ch) { return st; } -static void *php_http_curle_ctor(void *opaque, void *init_arg TSRMLS_DC) +static void *php_http_curle_ctor(void *opaque, void *init_arg) { void *ch; @@ -121,7 +90,7 @@ static void *php_http_curle_ctor(void *opaque, void *init_arg TSRMLS_DC) return NULL; } -static void *php_http_curle_copy(void *opaque, void *handle TSRMLS_DC) +static void *php_http_curle_copy(void *opaque, void *handle) { void *ch; @@ -133,7 +102,7 @@ static void *php_http_curle_copy(void *opaque, void *handle TSRMLS_DC) return NULL; } -static void php_http_curle_dtor(void *opaque, void *handle TSRMLS_DC) +static void php_http_curle_dtor(void *opaque, void *handle) { php_http_curle_storage_t *st = php_http_curle_get_storage(handle); @@ -156,14 +125,31 @@ static php_resource_factory_ops_t php_http_curle_resource_factory_ops = { php_http_curle_dtor }; -static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC) +static void *php_http_curlm_ctor(void *opaque, void *init_arg) { - return curl_multi_init(); + php_http_client_curl_handle_t *curl = calloc(1, sizeof(*curl)); + + if (!(curl->multi = curl_multi_init())) { + free(curl); + return NULL; + } + if (!(curl->share = curl_share_init())) { + curl_multi_cleanup(curl->multi); + free(curl); + return NULL; + } + curl_share_setopt(curl->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + curl_share_setopt(curl->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); + return curl; } -static void php_http_curlm_dtor(void *opaque, void *handle TSRMLS_DC) +static void php_http_curlm_dtor(void *opaque, void *handle) { - curl_multi_cleanup(handle); + php_http_client_curl_handle_t *curl = handle; + + curl_share_cleanup(curl->share); + curl_multi_cleanup(curl->multi); + free(handle); } static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { @@ -176,15 +162,10 @@ static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, void *ctx) { - php_http_message_body_t *body = ctx; + php_stream *s = php_http_message_body_stream(ctx); - if (body && body->stream_id) { - php_stream *s = php_http_message_body_stream(body); - - if (s) { - TSRMLS_FETCH_FROM_CTX(body->ts); - return php_stream_read(s, data, len * n); - } else abort(); + if (s) { + return php_stream_read(s, data, len * n); } return 0; } @@ -196,22 +177,19 @@ static int php_http_curle_progress_callback(void *ctx, double dltotal, double dl #endif { php_http_client_curl_handler_t *h = ctx; - zend_bool update = 0; if (h->progress.dl.total != dltotal || h->progress.dl.now != dlnow || h->progress.ul.total != ultotal || h->progress.ul.now != ulnow ) { - update = 1; - h->progress.dl.total = dltotal; h->progress.dl.now = dlnow; h->progress.ul.total = ultotal; h->progress.ul.now = ulnow; } - if (update && h->client->callback.progress.func) { + if (h->client->callback.progress.func) { h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); } @@ -221,7 +199,6 @@ static int php_http_curle_progress_callback(void *ctx, double dltotal, double dl static int php_http_curle_seek_callback(void *userdata, curl_off_t offset, int origin) { php_http_message_body_t *body = userdata; - TSRMLS_FETCH_FROM_CTX(body->ts); if (!body) { return 1; @@ -235,11 +212,13 @@ static int php_http_curle_seek_callback(void *userdata, curl_off_t offset, int o static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx) { php_http_client_curl_handler_t *h = ctx; + unsigned utype = PHP_HTTP_CLIENT_DEBUG_INFO; /* catch progress */ switch (type) { case CURLINFO_TEXT: if (data[0] == '-') { + goto text; } else if (php_memnstr(data, ZEND_STRL("Adding handle:"), data + length)) { h->progress.info = "setup"; } else if (php_memnstr(data, ZEND_STRL("addHandle"), data + length)) { @@ -256,8 +235,16 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, h->progress.info = "connected"; } else if (php_memnstr(data, ZEND_STRL("blacklisted"), data + length)) { h->progress.info = "blacklist check"; + } else if (php_memnstr(data, ZEND_STRL("TLS"), data + length)) { + h->progress.info = "ssl negotiation"; } else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) { h->progress.info = "ssl negotiation"; + } else if (php_memnstr(data, ZEND_STRL("certificate"), data + length)) { + h->progress.info = "ssl negotiation"; + } else if (php_memnstr(data, ZEND_STRL("ALPN"), data + length)) { + h->progress.info = "alpn"; + } else if (php_memnstr(data, ZEND_STRL("NPN"), data + length)) { + h->progress.info = "npn"; } else if (php_memnstr(data, ZEND_STRL("upload"), data + length)) { h->progress.info = "uploaded"; } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) { @@ -269,6 +256,7 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, } else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) { h->progress.info = "timeout"; } else { + text:; #if 0 h->progress.info = data; data[length - 1] = '\0'; @@ -278,20 +266,43 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); } break; + case CURLINFO_HEADER_OUT: - case CURLINFO_DATA_OUT: + utype |= PHP_HTTP_CLIENT_DEBUG_HEADER; + goto data_out; + case CURLINFO_SSL_DATA_OUT: + utype |= PHP_HTTP_CLIENT_DEBUG_SSL; + goto data_out; + + case CURLINFO_DATA_OUT: + data_out: + utype |= PHP_HTTP_CLIENT_DEBUG_OUT; h->progress.info = "send"; break; + case CURLINFO_HEADER_IN: - case CURLINFO_DATA_IN: + utype |= PHP_HTTP_CLIENT_DEBUG_HEADER; + goto data_in; + case CURLINFO_SSL_DATA_IN: + utype |= PHP_HTTP_CLIENT_DEBUG_SSL; + goto data_in; + + case CURLINFO_DATA_IN: + data_in: + utype |= PHP_HTTP_CLIENT_DEBUG_IN; h->progress.info = "receive"; break; + default: break; } + if (h->client->callback.debug.func) { + h->client->callback.debug.func(h->client->callback.debug.arg, h->client, &h->queue, utype, data, length); + } + #if 0 /* debug */ _dpf(type, data, length); @@ -316,131 +327,185 @@ static int php_http_curle_body_callback(char *data, size_t n, size_t l, void *ar 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_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)) { - add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1); + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "primary_ip", lenof("primary_ip"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,19,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) { - add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d); + ZVAL_DOUBLE(&tmp, d); + zend_hash_str_update(info, "appconnect_time", lenof("appconnect_time"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,19,4) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) { - add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "condition_unmet", lenof("condition_unmet"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,21,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) { - add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "primary_port", lenof("primary_port"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,21,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) { - add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1); + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "local_ip", lenof("local_ip"), &tmp); } #endif #if PHP_HTTP_CURL_VERSION(7,21,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) { - add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l); + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "local_port", lenof("local_port"), &tmp); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,50,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_VERSION, &l)) { + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "http_version", lenof("http_version"), &tmp); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,52,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXY_SSL_VERIFYRESULT, &l)) { + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "proxy_ssl_verifyresult", lenof("proxy_ssl_verifyresult"), &tmp); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,52,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROTOCOL, &l)) { + ZVAL_LONG(&tmp, l); + zend_hash_str_update(info, "protocol", lenof("protocol"), &tmp); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,52,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SCHEME, &c)) { + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "scheme", lenof("scheme"), &tmp); } #endif @@ -448,16 +513,18 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) #if PHP_HTTP_CURL_VERSION(7,34,0) { - zval *ti_array; + zval ti_array, subarray; struct curl_tlssessioninfo *ti; +#if PHP_HTTP_CURL_VERSION(7,48,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SSL_PTR, &ti)) { +#else if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SESSION, &ti)) { - const char *backend; +#endif + char *backend; - MAKE_STD_ZVAL(subarray); - ZVAL_NULL(subarray); - MAKE_STD_ZVAL(ti_array); - array_init(ti_array); + ZVAL_NULL(&subarray); + array_init(&ti_array); switch (ti->backend) { case CURLSSLBACKEND_NONE: @@ -465,33 +532,42 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) break; case CURLSSLBACKEND_OPENSSL: backend = "openssl"; -#ifdef PHP_HTTP_HAVE_OPENSSL +#if PHP_HTTP_HAVE_LIBCURL_OPENSSL { +#if PHP_HTTP_CURL_VERSION(7,48,0) + SSL *ssl = ti->internals; + SSL_CTX *ctx = ssl ? SSL_get_SSL_CTX(ssl) : NULL; +#else SSL_CTX *ctx = ti->internals; +#endif - array_init(subarray); - add_assoc_long_ex(subarray, ZEND_STRS("number"), SSL_CTX_sess_number(ctx)); - add_assoc_long_ex(subarray, ZEND_STRS("connect"), SSL_CTX_sess_connect(ctx)); - add_assoc_long_ex(subarray, ZEND_STRS("connect_good"), SSL_CTX_sess_connect_good(ctx)); - add_assoc_long_ex(subarray, ZEND_STRS("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx)); - add_assoc_long_ex(subarray, ZEND_STRS("hits"), SSL_CTX_sess_hits(ctx)); - add_assoc_long_ex(subarray, ZEND_STRS("cache_full"), SSL_CTX_sess_cache_full(ctx)); + array_init(&subarray); + if (ctx) { + add_assoc_long_ex(&subarray, ZEND_STRL("number"), SSL_CTX_sess_number(ctx)); + add_assoc_long_ex(&subarray, ZEND_STRL("connect"), SSL_CTX_sess_connect(ctx)); + add_assoc_long_ex(&subarray, ZEND_STRL("connect_good"), SSL_CTX_sess_connect_good(ctx)); + add_assoc_long_ex(&subarray, ZEND_STRL("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx)); + add_assoc_long_ex(&subarray, ZEND_STRL("hits"), SSL_CTX_sess_hits(ctx)); + add_assoc_long_ex(&subarray, ZEND_STRL("cache_full"), SSL_CTX_sess_cache_full(ctx)); + } } #endif break; case CURLSSLBACKEND_GNUTLS: backend = "gnutls"; -#ifdef PHP_HTTP_HAVE_GNUTLS +#if PHP_HTTP_HAVE_LIBCURL_GNUTLS { gnutls_session_t sess = ti->internals; char *desc; - array_init(subarray); - if ((desc = gnutls_session_get_desc(sess))) { - add_assoc_string_ex(subarray, ZEND_STRS("desc"), desc, 1); - gnutls_free(desc); + array_init(&subarray); + if (sess) { + if ((desc = gnutls_session_get_desc(sess))) { + add_assoc_string_ex(&subarray, ZEND_STRL("desc"), desc); + gnutls_free(desc); + } + add_assoc_bool_ex(&subarray, ZEND_STRL("resumed"), gnutls_session_is_resumed(sess)); } - add_assoc_bool_ex(subarray, ZEND_STRS("resumed"), gnutls_session_is_resumed(sess)); } #endif break; @@ -522,51 +598,54 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) default: backend = "unknown"; } - add_assoc_string_ex(ti_array, ZEND_STRS("backend"), estrdup(backend), 0); - add_assoc_zval_ex(ti_array, ZEND_STRS("internals"), subarray); - add_assoc_zval_ex(&array, "tls_session", sizeof("tls_session"), ti_array); + add_assoc_string_ex(&ti_array, ZEND_STRL("backend"), backend); + add_assoc_zval_ex(&ti_array, ZEND_STRL("internals"), &subarray); + zend_hash_str_update(info, "tls_session", lenof("tls_session"), &ti_array); } } #endif -#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT)) +#if (PHP_HTTP_CURL_VERSION(7,19,1) && PHP_HTTP_HAVE_LIBCURL_OPENSSL) || \ + (PHP_HTTP_CURL_VERSION(7,34,0) && PHP_HTTP_HAVE_LIBCURL_NSS) || \ + (PHP_HTTP_CURL_VERSION(7,42,0) && PHP_HTTP_HAVE_LIBCURL_GNUTLS) || \ + (PHP_HTTP_CURL_VERSION(7,39,0) && PHP_HTTP_HAVE_LIBCURL_GSKIT) { int i; - zval *ci_array; + zval ci_array, subarray; struct curl_certinfo *ci; char *colon, *keyname; if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) { - MAKE_STD_ZVAL(ci_array); - array_init(ci_array); + array_init(&ci_array); for (i = 0; i < ci->num_of_certs; ++i) { s = ci->certinfo[i]; - MAKE_STD_ZVAL(subarray); - array_init(subarray); + array_init(&subarray); for (p = s; p; p = p->next) { if (p->data) { if ((colon = strchr(p->data, ':'))) { keyname = estrndup(p->data, colon - p->data); - add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1); + add_assoc_string_ex(&subarray, keyname, colon - p->data, colon + 1); efree(keyname); } else { - add_next_index_string(subarray, p->data, 1); + add_next_index_string(&subarray, p->data); } } } - add_next_index_zval(ci_array, subarray); + add_next_index_zval(&ci_array, &subarray); } - add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array); + zend_hash_str_update(info, "certinfo", lenof("certinfo"), &ci_array); } } #endif { php_http_curle_storage_t *st = php_http_curle_get_storage(ch); - add_assoc_long_ex(&array, "curlcode", sizeof("curlcode"), st->errorcode); - add_assoc_string_ex(&array, "error", sizeof("error"), st->errorbuffer, 1); + ZVAL_LONG(&tmp, st->errorcode); + zend_hash_str_update(info, "curlcode", lenof("curlcode"), &tmp); + ZVAL_STRING(&tmp, st->errorbuffer); + zend_hash_str_update(info, "error", lenof("error"), &tmp); } return SUCCESS; @@ -577,14 +656,14 @@ static int compare_queue(php_http_client_enqueue_t *e, void *handle) 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) +static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_handler_t *h) { php_http_message_t *response; php_http_header_parser_t parser; - zval *zh; + zval *zh, tmp; - response = php_http_message_init(NULL, 0, h->response.body TSRMLS_CC); - php_http_header_parser_init(&parser TSRMLS_CC); + response = php_http_message_init(NULL, 0, h->response.body); + php_http_header_parser_init(&parser); while (h->response.headers.used) { php_http_header_parser_state_t st = php_http_header_parser_parse(&parser, &h->response.headers, PHP_HTTP_HEADER_PARSER_CLEANUP, &response->hdrs, @@ -609,36 +688,39 @@ static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_ha 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")))) { + ZVAL_COPY(&tmp, zh); + zend_hash_str_update(&response->hdrs, "X-Original-Content-Length", lenof("X-Original-Content-Length"), &tmp); } - 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")))) { + ZVAL_COPY(&tmp, zh); + zend_hash_str_del(&response->hdrs, "Transfer-Encoding", lenof("Transfer-Encoding")); + zend_hash_str_update(&response->hdrs, "X-Original-Transfer-Encoding", lenof("X-Original-Transfer-Encoding"), &tmp); } - 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")))) { + ZVAL_COPY(&tmp, zh); + zend_hash_str_del(&response->hdrs, "Content-Range", lenof("Content-Range")); + zend_hash_str_update(&response->hdrs, "X-Original-Content-Range", lenof("X-Original-Content-Range"), &tmp); } - 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")))) { + ZVAL_COPY(&tmp, zh); + zend_hash_str_del(&response->hdrs, "Content-Encoding", lenof("Content-Encoding")); + zend_hash_str_update(&response->hdrs, "X-Original-Content-Encoding", lenof("X-Original-Content-Encoding"), &tmp); } php_http_message_update_headers(response); return response; } -static void php_http_curlm_responsehandler(php_http_client_t *context) +void php_http_client_curl_responsehandler(php_http_client_t *context) { int err_count = 0, remaining = 0; php_http_curle_storage_t *st, *err = NULL; php_http_client_enqueue_t *enqueue; php_http_client_curl_t *curl = context->ctx; - TSRMLS_FETCH_FROM_CTX(context->ts); do { - CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining); + CURLMsg *msg = curl_multi_info_read(curl->handle->multi, &remaining); if (msg && CURLMSG_DONE == msg->msg) { if (CURLE_OK != msg->data.result) { @@ -658,7 +740,7 @@ static void php_http_curlm_responsehandler(php_http_client_t *context) if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) { php_http_client_curl_handler_t *handler = enqueue->opaque; - php_http_message_t *response = php_http_curlm_responseparser(handler TSRMLS_CC); + php_http_message_t *response = php_http_curlm_responseparser(handler); if (response) { context->callback.response.func(context->callback.response.arg, context, &handler->queue, &response); @@ -672,7 +754,7 @@ static void php_http_curlm_responsehandler(php_http_client_t *context) int i = 0; do { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s; %s (%s)", curl_easy_strerror(err[i].errorcode), err[i].errorbuffer, STR_PTR(err[i].url)); + php_error_docref(NULL, E_WARNING, "%s; %s (%s)", curl_easy_strerror(err[i].errorcode), err[i].errorbuffer, STR_PTR(err[i].url)); if (err[i].url) { efree(err[i].url); } @@ -682,161 +764,26 @@ static void php_http_curlm_responsehandler(php_http_client_t *context) } } -#if PHP_HTTP_HAVE_EVENT - -typedef struct php_http_curlm_event { - struct event evnt; - php_http_client_t *context; -} php_http_curlm_event_t; - -static inline int etoca(short action) { - switch (action & (EV_READ|EV_WRITE)) { - case EV_READ: - return CURL_CSELECT_IN; - break; - case EV_WRITE: - return CURL_CSELECT_OUT; - break; - case EV_READ|EV_WRITE: - return CURL_CSELECT_IN|CURL_CSELECT_OUT; - break; - default: - return 0; - } -} - -static void php_http_curlm_timeout_callback(int socket, short action, void *event_data) -{ - php_http_client_t *context = event_data; - php_http_client_curl_t *curl = context->ctx; - -#if DBG_EVENTS - fprintf(stderr, "T"); -#endif - if (curl->useevents) { - CURLMcode rc; - TSRMLS_FETCH_FROM_CTX(context->ts); - - /* ignore and use -1,0 on timeout */ - (void) socket; - (void) action; - - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished))); - - if (CURLM_OK != rc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); - } - - php_http_curlm_responsehandler(context); - } -} - -static void php_http_curlm_event_callback(int socket, short action, void *event_data) -{ - php_http_client_t *context = event_data; - php_http_client_curl_t *curl = context->ctx; - -#if DBG_EVENTS - fprintf(stderr, "E"); -#endif - if (curl->useevents) { - CURLMcode rc = CURLM_OK; - TSRMLS_FETCH_FROM_CTX(context->ts); - - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished))); - - if (CURLM_OK != rc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); - } - - php_http_curlm_responsehandler(context); - - /* remove timeout if there are no transfers left */ - if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) { - event_del(curl->timeout); - } - } -} - -static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data) +void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action) { - php_http_client_t *context = socket_data; - php_http_client_curl_t *curl = context->ctx; + CURLMcode rc; + php_http_client_curl_t *curl = client->ctx; #if DBG_EVENTS - fprintf(stderr, "S"); + fprintf(stderr, "H"); #endif - if (curl->useevents) { - int events = EV_PERSIST; - php_http_curlm_event_t *ev = assign_data; - TSRMLS_FETCH_FROM_CTX(context->ts); - - if (!ev) { - ev = ecalloc(1, sizeof(php_http_curlm_event_t)); - ev->context = context; - curl_multi_assign(curl->handle, sock, ev); - } else { - event_del(&ev->evnt); - } - switch (action) { - case CURL_POLL_IN: - events |= EV_READ; - break; - case CURL_POLL_OUT: - events |= EV_WRITE; - break; - case CURL_POLL_INOUT: - events |= EV_READ|EV_WRITE; - break; - - case CURL_POLL_REMOVE: - efree(ev); - /* no break */ - case CURL_POLL_NONE: - return 0; - - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action); - return -1; - } + do { + rc = curl_multi_socket_action(curl->handle->multi, s, curl_action, &curl->unfinished); + } while (CURLM_CALL_MULTI_PERFORM == rc); - event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context); - event_add(&ev->evnt, NULL); + if (CURLM_OK != rc) { + php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc)); } - return 0; + php_http_client_curl_responsehandler(client); } -static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data) -{ - php_http_client_t *context = timer_data; - php_http_client_curl_t *curl = context->ctx; - -#if DBG_EVENTS - fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms); -#endif - if (curl->useevents) { - - if (timeout_ms < 0) { - php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context); - } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) { - struct timeval timeout; - - if (!event_initialized(curl->timeout)) { - event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context); - } - - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - - event_add(curl->timeout, &timeout); - } - } -} - -#endif /* HAVE_EVENT */ - /* curl options */ static php_http_options_t php_http_curle_options, php_http_curlm_options; @@ -850,9 +797,26 @@ static ZEND_RESULT_CODE php_http_curle_option_set_ssl_verifyhost(php_http_option php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_BVAL_P(val) ? 2 : 0)) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_TYPE_P(val) == IS_TRUE ? 2 : 0)) { + return FAILURE; + } + return SUCCESS; +} + +static ZEND_RESULT_CODE php_http_curle_option_set_cookiesession(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIESESSION, (long) (Z_TYPE_P(val) == IS_TRUE))) { return FAILURE; } + if (Z_TYPE_P(val) == IS_TRUE) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIELIST, "SESS")) { + return FAILURE; + } + } + return SUCCESS; } @@ -865,7 +829,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t if (storage->cookiestore) { pefree(storage->cookiestore, 1); } - if (val && Z_STRLEN_P(val)) { + if (val && Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val)) { storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1); } else { storage->cookiestore = NULL; @@ -875,6 +839,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t ) { return FAILURE; } + return SUCCESS; } @@ -882,11 +847,12 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookies(php_http_option_t *opt { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); if (val && Z_TYPE_P(val) != IS_NULL) { + HashTable *ht = HASH_OF(val); + if (curl->options.encode_cookies) { - if (SUCCESS == php_http_url_encode_hash_ex(HASH_OF(val), &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0 TSRMLS_CC)) { + if (SUCCESS == php_http_url_encode_hash_ex(ht, &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0)) { php_http_buffer_fix(&curl->options.cookies); if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { return FAILURE; @@ -895,19 +861,20 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookies(php_http_option_t *opt return FAILURE; } } else { - HashPosition pos; - php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0); - zval **cookie_val; + php_http_arrkey_t cookie_key; + zval *cookie_val; - FOREACH_KEYVAL(pos, val, cookie_key, cookie_val) { - zval *zv = php_http_ztyp(IS_STRING, *cookie_val); + ZEND_HASH_FOREACH_KEY_VAL(ht, cookie_key.h, cookie_key.key, cookie_val) + { + zend_string *zs = zval_get_string(cookie_val); - php_http_array_hashkey_stringify(&cookie_key); - php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(zv)); - php_http_array_hashkey_stringfree(&cookie_key); + php_http_arrkey_stringify(&cookie_key, NULL); + php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.key->val, zs->val); + php_http_arrkey_dtor(&cookie_key); - zval_ptr_dtor(&zv); + zend_string_release(zs); } + ZEND_HASH_FOREACH_END(); php_http_buffer_fix(&curl->options.cookies); if (curl->options.cookies.used) { @@ -929,7 +896,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_encodecookies(php_http_option_ { php_http_client_curl_handler_t *curl = userdata; - curl->options.encode_cookies = Z_BVAL_P(val); + curl->options.encode_cookies = Z_TYPE_P(val) == IS_TRUE; return SUCCESS; } @@ -937,7 +904,6 @@ static ZEND_RESULT_CODE php_http_curle_option_set_lastmodified(php_http_option_t { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); if (Z_LVAL_P(val)) { if (Z_LVAL_P(val) > 0) { @@ -945,7 +911,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_lastmodified(php_http_option_t return FAILURE; } } else { - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) sapi_get_request_time(TSRMLS_C) + Z_LVAL_P(val))) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) sapi_get_request_time() + Z_LVAL_P(val))) { return FAILURE; } } @@ -970,7 +936,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_compress(php_http_option_t *op #if !PHP_HTTP_CURL_VERSION(7,21,6) # define CURLOPT_ACCEPT_ENCODING CURLOPT_ENCODING #endif - 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; @@ -981,7 +947,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_etag(php_http_option_t *opt, z php_http_client_curl_handler_t *curl = userdata; php_http_buffer_t header; - if (Z_STRLEN_P(val)) { + if (val && Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val)) { zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"')); php_http_buffer_init(&header); php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val)); @@ -996,32 +962,32 @@ static ZEND_RESULT_CODE php_http_curle_option_set_range(php_http_option_t *opt, { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); php_http_buffer_reset(&curl->options.ranges); if (val && Z_TYPE_P(val) != IS_NULL) { - HashPosition pos; - zval **rr, **rb, **re; - - FOREACH_VAL(pos, val, rr) { - if (Z_TYPE_PP(rr) == IS_ARRAY) { - if (2 == php_http_array_list(Z_ARRVAL_PP(rr) TSRMLS_CC, 2, &rb, &re)) { - if ( ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) && - ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) { - zval *rbl = php_http_ztyp(IS_LONG, *rb); - zval *rel = php_http_ztyp(IS_LONG, *re); - - if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) { - php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel)); + zval *rr, *rb, *re; + HashTable *ht = HASH_OF(val); + + ZEND_HASH_FOREACH_VAL(ht, rr) + { + if (Z_TYPE_P(rr) == IS_ARRAY) { + if (2 == php_http_array_list(Z_ARRVAL_P(rr), 2, &rb, &re)) { + zend_long rbl = zval_get_long(rb), rel = zval_get_long(re); + + if (rbl >= 0) { + if (rel > 0) { + php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", rbl, rel); + } else { + php_http_buffer_appendf(&curl->options.ranges, "%ld-", rbl); } - zval_ptr_dtor(&rbl); - zval_ptr_dtor(&rel); + } else if (rel > 0) { + php_http_buffer_appendf(&curl->options.ranges, "-%ld", rel); } - } } } + ZEND_HASH_FOREACH_END(); if (curl->options.ranges.used) { curl->options.range_request = 1; @@ -1084,26 +1050,16 @@ static ZEND_RESULT_CODE php_http_curle_option_set_portrange(php_http_option_t *o php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; long localport = 0, localportrange = 0; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); if (val && Z_TYPE_P(val) != IS_NULL) { - zval **z_port_start, *zps_copy = NULL, **z_port_end, *zpe_copy = NULL; + zval *zps, *zpe; - switch (php_http_array_list(Z_ARRVAL_P(val) TSRMLS_CC, 2, &z_port_start, &z_port_end)) { + switch (php_http_array_list(Z_ARRVAL_P(val), 2, &zps, &zpe)) { case 2: - zps_copy = php_http_ztyp(IS_LONG, *z_port_start); - zpe_copy = php_http_ztyp(IS_LONG, *z_port_end); - localportrange = labs(Z_LVAL_P(zps_copy)-Z_LVAL_P(zpe_copy))+1L; + localportrange = labs(zval_get_long(zps)-zval_get_long(zpe))+1L; /* no break */ case 1: - if (!zps_copy) { - zps_copy = php_http_ztyp(IS_LONG, *z_port_start); - } - localport = (zpe_copy && Z_LVAL_P(zpe_copy) > 0) ? MIN(Z_LVAL_P(zps_copy), Z_LVAL_P(zpe_copy)) : Z_LVAL_P(zps_copy); - zval_ptr_dtor(&zps_copy); - if (zpe_copy) { - zval_ptr_dtor(&zpe_copy); - } + localport = (zval_get_long(zpe) > 0) ? MIN(zval_get_long(zps), zval_get_long(zpe)) : zval_get_long(zps); break; default: break; @@ -1121,26 +1077,28 @@ static ZEND_RESULT_CODE php_http_curle_option_set_portrange(php_http_option_t *o 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); + zend_string_release(zs); + 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_HASH_FOREACH_END(); php_http_buffer_dtor(&header); } if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, curl->options.proxyheaders)) { @@ -1159,18 +1117,18 @@ static ZEND_RESULT_CODE php_http_curle_option_set_resolve(php_http_option_t *opt { php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); if (val && Z_TYPE_P(val) != IS_NULL) { - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - HashPosition pos; - zval **data; - - FOREACH_KEYVAL(pos, val, key, data) { - zval *cpy = php_http_ztyp(IS_STRING, *data); - curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy)); - zval_ptr_dtor(&cpy); + HashTable *ht = HASH_OF(val); + zval *data; + + ZEND_HASH_FOREACH_VAL(ht, data) + { + zend_string *zs = zval_get_string(data); + curl->options.resolve = curl_slist_append(curl->options.resolve, zs->val); + zend_string_release(zs); } + ZEND_HASH_FOREACH_END(); if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) { return FAILURE; @@ -1184,7 +1142,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_resolve(php_http_option_t *opt } #endif -#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP) +#if PHP_HTTP_CURL_VERSION(7,21,4) && PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE 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; @@ -1193,7 +1151,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_ssl_tlsauthtype(php_http_optio 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)) { + if (CURLE_OK == curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_LIBCURL_TLSAUTH_SRP)) { return SUCCESS; } /* no break */ @@ -1201,26 +1159,24 @@ static ZEND_RESULT_CODE php_http_curle_option_set_ssl_tlsauthtype(php_http_optio return FAILURE; } } - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_CURL_TLSAUTH_DEF)) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_LIBCURL_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; /* url options */ #if PHP_HTTP_CURL_VERSION(7,42,0) - php_http_option_register(registry, ZEND_STRL("path_as_is"), CURLOPT_PATH_AS_IS, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("path_as_is"), CURLOPT_PATH_AS_IS, _IS_BOOL); #endif /* proxy */ - if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - } + php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING); php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG); php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG); if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) { @@ -1229,7 +1185,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG))) { Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE; } - php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,19,4) php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING); #endif @@ -1240,15 +1196,19 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) } #endif #if PHP_HTTP_CURL_VERSION(7,43,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("proxy_service_name"), CURLOPT_PROXY_SERVICE_NAME, IS_STRING))) { + if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_GSSAPI) + && (opt = php_http_option_register(registry, ZEND_STRL("proxy_service_name"), CURLOPT_PROXY_SERVICE_NAME, IS_STRING)) + ) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif #if PHP_HTTP_CURL_VERSION(7,40,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_UNIX_SOCKETS)) { + if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } } #endif @@ -1262,7 +1222,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) opt->setter = php_http_curle_option_set_resolve; } #endif -#if PHP_HTTP_HAVE_ARES +#if PHP_HTTP_HAVE_LIBCURL_ARES # if PHP_HTTP_CURL_VERSION(7,24,0) if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; @@ -1296,8 +1256,8 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) Z_LVAL(opt->defval) = 5; } */ - php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL); - php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, _IS_BOOL); + php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, _IS_BOOL); /* outgoing interface */ php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING); @@ -1321,6 +1281,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE; } #if PHP_HTTP_CURL_VERSION(7,43,0) + if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSPI) || PHP_HTTP_CURL_FEATURE(CURL_VERSION_GSSAPI)) if ((opt = php_http_option_register(registry, ZEND_STRL("service_name"), CURLOPT_SERVICE_NAME, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } @@ -1330,7 +1291,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) { opt->setter = php_http_curle_option_set_redirect; } - php_http_option_register(registry, ZEND_STRL("unrestricted_auth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("unrestricted_auth"), CURLOPT_UNRESTRICTED_AUTH, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,19,1) php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_LONG); #endif @@ -1347,18 +1308,17 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } - if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) { + if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, _IS_BOOL))) { ZVAL_BOOL(&opt->defval, 1); } /* useragent */ if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) { /* don't check strlen, to allow sending no useragent at all */ - ZVAL_STRING(&opt->defval, + ZVAL_PSTRING(&opt->defval, "PECL_HTTP/" PHP_PECL_HTTP_VERSION " " "PHP/" PHP_VERSION " " - "libcurl/" LIBCURL_VERSION - , 0); + "libcurl/" LIBCURL_VERSION); } /* resume */ @@ -1377,7 +1337,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) } /* compression */ - if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) { + if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, _IS_BOOL))) { opt->setter = php_http_curle_option_set_compress; } @@ -1387,7 +1347,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) } /* cookies */ - if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) { + if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, _IS_BOOL))) { opt->setter = php_http_curle_option_set_encodecookies; ZVAL_BOOL(&opt->defval, 1); } @@ -1396,7 +1356,9 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) } /* cookiesession, don't load session cookies from cookiestore */ - php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL); + if ((opt = php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, _IS_BOOL))) { + opt->setter = php_http_curle_option_set_cookiesession; + } /* cookiestore, read initial cookies from that file and store cookies back into that file */ if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; @@ -1426,9 +1388,9 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) #endif /* tcp */ - php_http_option_register(registry, ZEND_STRL("tcp_nodelay"), CURLOPT_TCP_NODELAY, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("tcp_nodelay"), CURLOPT_TCP_NODELAY, _IS_BOOL); #if PHP_HTTP_CURL_VERSION(7,25,0) - php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, _IS_BOOL); if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) { Z_LVAL(opt->defval) = 60; } @@ -1438,104 +1400,115 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) #endif /* ssl */ - if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) { - registry = &opt->suboptions; + if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSL)) { + if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) { + registry = &opt->suboptions; - if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - ZVAL_STRING(&opt->defval, "PEM", 0); - } - if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - ZVAL_STRING(&opt->defval, "PEM", 0); - } - if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - } - php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING); - php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG); - if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) { - ZVAL_BOOL(&opt->defval, 1); - } - if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) { - ZVAL_BOOL(&opt->defval, 1); - opt->setter = php_http_curle_option_set_ssl_verifyhost; - } -#if PHP_HTTP_CURL_VERSION(7,41,0) - php_http_option_register(registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, IS_BOOL); + if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + ZVAL_PSTRING(&opt->defval, "PEM"); + } + if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + ZVAL_PSTRING(&opt->defval, "PEM"); + } + if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING); + php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG); + if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, _IS_BOOL))) { + ZVAL_BOOL(&opt->defval, 1); + } + if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, _IS_BOOL))) { + ZVAL_BOOL(&opt->defval, 1); + opt->setter = php_http_curle_option_set_ssl_verifyhost; + } +#if PHP_HTTP_CURL_VERSION(7,41,0) && (PHP_HTTP_HAVE_LIBCURL_OPENSSL || PHP_HTTP_HAVE_LIBCURL_NSS || PHP_HTTP_HAVE_LIBCURL_GNUTLS) + php_http_option_register(registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, _IS_BOOL); #endif - php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING); - if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; -#ifdef PHP_HTTP_CURL_CAINFO - ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0); + php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING); +#if PHP_HTTP_HAVE_LIBCURL_CAINFO + if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; +#ifdef PHP_HTTP_CAINFO + ZVAL_PSTRING(&opt->defval, PHP_HTTP_CAINFO); #endif - } - if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } + } +#endif +#if PHP_HTTP_HAVE_LIBCURL_CAPATH + if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; +#ifdef PHP_HTTP_CAPATH + ZVAL_PSTRING(&opt->defval, PHP_HTTP_CAPATH); +#endif + } +#endif + if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } #if PHP_HTTP_CURL_VERSION(7,19,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } -# ifdef PHP_HTTP_HAVE_OPENSSL - if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) { - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; - } + if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +# if PHP_HTTP_HAVE_LIBCURL_OPENSSL + if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } # endif #endif -#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT)) - php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL); +#if (PHP_HTTP_CURL_VERSION(7,19,1) && PHP_HTTP_HAVE_LIBCURL_OPENSSL) || (PHP_HTTP_CURL_VERSION(7,34,0) && PHP_HTTP_HAVE_LIBCURL_NSS) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_LIBCURL_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_LIBCURL_GSKIT)) + if ((opt = php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL))) { + ZVAL_FALSE(&opt->defval); + } #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))) { - ZVAL_BOOL(&opt->defval, 1); - } - if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, IS_BOOL))) { - ZVAL_BOOL(&opt->defval, 1); - } + 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))) { + ZVAL_BOOL(&opt->defval, 1); + } #endif #if PHP_HTTP_CURL_VERSION(7,39,0) - /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */ - 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; - } + /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */ + 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) && 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; - } +#if PHP_HTTP_CURL_VERSION(7,21,4) && PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE + 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 -#if PHP_HTTP_CURL_VERSION(7,42,0) && (defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_DARWINSSL)) - php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, IS_BOOL); +#if PHP_HTTP_CURL_VERSION(7,42,0) && (PHP_HTTP_HAVE_LIBCURL_NSS || PHP_HTTP_HAVE_LIBCURL_SECURETRANSPORT) + php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, _IS_BOOL); #endif + } } } @@ -1545,8 +1518,12 @@ static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *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); + zval zopt; + + ZVAL_DUP(&zopt, option); + convert_to_explicit_type(&zopt, opt->type); + zend_hash_update(&curl->options.cache, opt->name, &zopt); + return zend_hash_find(&curl->options.cache, opt->name); } return option; } @@ -1556,19 +1533,18 @@ static ZEND_RESULT_CODE php_http_curle_set_option(php_http_option_t *opt, zval * php_http_client_curl_handler_t *curl = userdata; CURL *ch = curl->handle; zval tmp; - CURLcode rc = CURLE_OK; + CURLcode rc = CURLE_UNKNOWN_OPTION; ZEND_RESULT_CODE rv = SUCCESS; - TSRMLS_FETCH_FROM_CTX(curl->client->ts); if (!val) { val = &opt->defval; } switch (opt->type) { - case IS_BOOL: + case _IS_BOOL: if (opt->setter) { rv = opt->setter(opt, val, curl); - } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) { + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) (Z_TYPE_P(val) == IS_TRUE))) { rv = FAILURE; } break; @@ -1584,11 +1560,15 @@ static ZEND_RESULT_CODE php_http_curle_set_option(php_http_option_t *opt, zval * case IS_STRING: if (opt->setter) { rv = opt->setter(opt, val, curl); + } else if (!val || Z_TYPE_P(val) == IS_NULL) { + if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) { + rv = FAILURE; + } } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) && !Z_STRLEN_P(val)) { if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) { rv = FAILURE; } - } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) && Z_STRVAL_P(val) && SUCCESS != php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) { + } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) && Z_STRVAL_P(val) && SUCCESS != php_check_open_basedir(Z_STRVAL_P(val))) { if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) { rv = FAILURE; } @@ -1627,7 +1607,7 @@ static ZEND_RESULT_CODE php_http_curle_set_option(php_http_option_t *opt, zval * break; } if (rv != SUCCESS) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_easy_strerror(rc)); + php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc)); } return rv; } @@ -1637,15 +1617,13 @@ static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_ { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; - CURLM *ch = curl->handle; + CURLM *ch = curl->handle->multi; HashTable tmp_ht; char **bl = NULL; - TSRMLS_FETCH_FROM_CTX(client->ts); /* array of char *, ending with a NULL */ if (value && Z_TYPE_P(value) != IS_NULL) { - zval **entry; - HashPosition pos; + zval *entry; HashTable *ht = HASH_OF(value); int c = zend_hash_num_elements(ht); char **ptr = ecalloc(c + 1, sizeof(char *)); @@ -1655,9 +1633,11 @@ static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_ zend_hash_init(&tmp_ht, c, NULL, ZVAL_PTR_DTOR, 0); array_join(ht, &tmp_ht, 0, ARRAY_JOIN_STRINGIFY); - FOREACH_HASH_VAL(pos, &tmp_ht, entry) { - *ptr++ = Z_STRVAL_PP(entry); + ZEND_HASH_FOREACH_VAL(&tmp_ht, entry) + { + *ptr++ = Z_STRVAL_P(entry); } + ZEND_HASH_FOREACH_END(); } if (CURLM_OK != curl_multi_setopt(ch, opt->option, bl)) { @@ -1676,27 +1656,24 @@ static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_ } #endif -#if PHP_HTTP_HAVE_EVENT -static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, zend_bool enable) +static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, php_http_client_curl_ops_t *ev_ops, zval *init_data) { php_http_client_curl_t *curl = h->ctx; + void *ev_ctx; - if ((curl->useevents = enable)) { - if (!curl->evbase) { - curl->evbase = event_base_new(); - } - if (!curl->timeout) { - curl->timeout = ecalloc(1, sizeof(struct event)); + if (ev_ops) { + if (!(ev_ctx = ev_ops->init(h, init_data))) { + return FAILURE; } - curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, h); - curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback); - curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h); - curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback); + curl->ev_ctx = ev_ctx; + curl->ev_ops = ev_ops; } else { - curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, NULL); - curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, NULL); - curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, NULL); - curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, NULL); + if (curl->ev_ops) { + if (curl->ev_ctx) { + curl->ev_ops->dtor(&curl->ev_ctx); + } + curl->ev_ops = NULL; + } } return SUCCESS; @@ -1705,12 +1682,60 @@ static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h static ZEND_RESULT_CODE php_http_curlm_option_set_use_eventloop(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; + php_http_client_curl_ops_t *ev_ops = NULL; - return php_http_curlm_use_eventloop(client, value && Z_BVAL_P(value)); + if (value && Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_get_class_entry())) { + ev_ops = php_http_client_curl_user_ops_get(); +#if PHP_HTTP_HAVE_LIBEVENT + } else if (value && zend_is_true(value)) { + ev_ops = php_http_client_curl_event_ops_get(); +#endif + } + + return php_http_curlm_use_eventloop(client, ev_ops, value); +} + +static ZEND_RESULT_CODE php_http_curlm_option_set_share_cookies(php_http_option_t *opt, zval *value, void *userdata) +{ + php_http_client_t *client = userdata; + php_http_client_curl_t *curl = client->ctx; + CURLSHcode rc; + + if (Z_TYPE_P(value) == IS_TRUE) { + rc = curl_share_setopt(curl->handle->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + } else { + rc = curl_share_setopt(curl->handle->share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE); + } + + if (CURLSHE_OK != rc) { + php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_share_strerror(rc)); + return FAILURE; + } + return SUCCESS; +} + +#if PHP_HTTP_CURL_VERSION(7,23,0) +static ZEND_RESULT_CODE php_http_curlm_option_set_share_ssl(php_http_option_t *opt, zval *value, void *userdata) +{ + php_http_client_t *client = userdata; + php_http_client_curl_t *curl = client->ctx; + CURLSHcode rc; + + if (Z_TYPE_P(value) == IS_TRUE) { + rc = curl_share_setopt(curl->handle->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); + } else { + rc = curl_share_setopt(curl->handle->share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_SSL_SESSION); + } + + if (CURLSHE_OK != rc) { + php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_share_strerror(rc)); + return FAILURE; + } + return SUCCESS; } #endif -static void php_http_curlm_options_init(php_http_options_t *registry TSRMLS_DC) +static void php_http_curlm_options_init(php_http_options_t *registry) { php_http_option_t *opt; @@ -1734,7 +1759,7 @@ static void php_http_curlm_options_init(php_http_options_t *registry TSRMLS_DC) php_http_option_register(registry, ZEND_STRL("max_total_connections"), CURLMOPT_MAX_TOTAL_CONNECTIONS, IS_LONG); #endif /* enable/disable HTTP pipelining */ - php_http_option_register(registry, ZEND_STRL("pipelining"), CURLMOPT_PIPELINING, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("pipelining"), CURLMOPT_PIPELINING, _IS_BOOL); /* chunk length threshold for pipelining */ #if PHP_HTTP_CURL_VERSION(7,30,0) php_http_option_register(registry, ZEND_STRL("chunk_length_penalty_size"), CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, IS_LONG); @@ -1756,10 +1781,19 @@ static void php_http_curlm_options_init(php_http_options_t *registry TSRMLS_DC) } #endif /* events */ -#if PHP_HTTP_HAVE_EVENT - if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, IS_BOOL))) { + if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, 0))) { opt->setter = php_http_curlm_option_set_use_eventloop; } + /* share */ + if ((opt = php_http_option_register(registry, ZEND_STRL("share_cookies"), 0, _IS_BOOL))) { + opt->setter = php_http_curlm_option_set_share_cookies; + ZVAL_TRUE(&opt->defval); + } +#if PHP_HTTP_CURL_VERSION(7,23,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("share_ssl"), 0, _IS_BOOL))) { + opt->setter = php_http_curlm_option_set_share_ssl; + ZVAL_TRUE(&opt->defval); + } #endif } @@ -1767,45 +1801,47 @@ static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval * { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; - CURLM *ch = curl->handle; - zval *orig = val; + CURLM *ch = curl->handle->multi; + zval zopt, *orig = val; CURLMcode rc = CURLM_UNKNOWN_OPTION; ZEND_RESULT_CODE rv = SUCCESS; - TSRMLS_FETCH_FROM_CTX(client->ts); if (!val) { val = &opt->defval; } else if (opt->type && Z_TYPE_P(val) != opt->type && !(Z_TYPE_P(val) == IS_NULL && opt->type == IS_ARRAY)) { - val = php_http_ztyp(opt->type, val); + ZVAL_DUP(&zopt, val); + convert_to_explicit_type(&zopt, opt->type); + + val = &zopt; } if (opt->setter) { rv = opt->setter(opt, val, client); } else { switch (opt->type) { - case IS_BOOL: - if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) Z_BVAL_P(val)))) { + case _IS_BOOL: + if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) zend_is_true(val)))) { rv = FAILURE; + php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_multi_strerror(rc)); } break; case IS_LONG: if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, Z_LVAL_P(val)))) { rv = FAILURE; + php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_multi_strerror(rc)); } break; default: rv = FAILURE; + php_error_docref(NULL, E_NOTICE, "Could not set option %s", opt->name->val); break; } } if (val && val != orig && val != &opt->defval) { - zval_ptr_dtor(&val); + zval_ptr_dtor(val); } - if (rv != SUCCESS) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_easy_strerror(rc)); - } return rv; } @@ -1826,6 +1862,7 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_ st->cookiestore = NULL; } st->errorbuffer[0] = '\0'; + st->errorcode = 0; } curl_easy_setopt(ch, CURLOPT_URL, NULL); @@ -1869,11 +1906,11 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_ static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf) { void *handle; + php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler; - TSRMLS_FETCH_FROM_CTX(h->ts); - if (!(handle = php_resource_factory_handle_ctor(rf, NULL TSRMLS_CC))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle"); + if (!(handle = php_resource_factory_handle_ctor(rf, NULL))) { + php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle"); return NULL; } @@ -1881,13 +1918,13 @@ static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_htt handler->rf = rf; handler->client = h; handler->handle = handle; - 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); -#if defined(ZTS) +#if ZTS curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); #endif curl_easy_setopt(handle, CURLOPT_HEADER, 0L); @@ -1910,6 +1947,7 @@ static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_htt curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler); curl_easy_setopt(handle, CURLOPT_WRITEDATA, handler); curl_easy_setopt(handle, CURLOPT_HEADERDATA, handler); + curl_easy_setopt(handle, CURLOPT_SHARE, curl->handle->share); php_http_client_curl_handler_reset(handler); @@ -1922,11 +1960,10 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_cur size_t body_size; php_http_message_t *msg = enqueue->request; php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); - TSRMLS_FETCH_FROM_CTX(curl->client->ts); /* request url */ if (!PHP_HTTP_INFO(msg).request.url) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL"); + php_error_docref(NULL, E_WARNING, "Cannot request empty URL"); return FAILURE; } storage->errorbuffer[0] = '\0'; @@ -1942,34 +1979,33 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_cur /* request headers */ php_http_message_update_headers(msg); if (zend_hash_num_elements(&msg->hdrs)) { - 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; + zend_string *header_str; php_http_buffer_t header; #if !PHP_HTTP_CURL_VERSION(7,23,0) - zval **ct = NULL; - - zend_hash_find(&msg->hdrs, ZEND_STRS("Content-Length"), (void *) &ct); + zval *ct = zend_hash_str_find(&msg->hdrs, ZEND_STRL("Content-Length")); #endif php_http_buffer_init(&header); - FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) { - if (header_key.type == HASH_KEY_IS_STRING) { + ZEND_HASH_FOREACH_KEY_VAL(&msg->hdrs, header_key.h, header_key.key, header_val) + { + if (header_key.key) { #if !PHP_HTTP_CURL_VERSION(7,23,0) /* avoid duplicate content-length header */ - if (ct && *ct == *header_val) { + if (ct && ct == header_val) { continue; } #endif - header_cpy = php_http_ztyp(IS_STRING, *header_val); - php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy)); + header_str = zval_get_string(header_val); + php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, header_str->val); php_http_buffer_fix(&header); curl->options.headers = curl_slist_append(curl->options.headers, header.data); php_http_buffer_reset(&header); - - zval_ptr_dtor(&header_cpy); + zend_string_release(header_str); } } + ZEND_HASH_FOREACH_END(); php_http_buffer_dtor(&header); } curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers); @@ -2019,7 +2055,7 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_cur curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method); } } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot use empty request method"); + php_error_docref(NULL, E_WARNING, "Cannot use empty request method"); return FAILURE; } @@ -2036,15 +2072,17 @@ static void php_http_client_curl_handler_clear(php_http_client_curl_handler_t *h #endif curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L); curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL); + curl_easy_setopt(handler->handle, CURLOPT_COOKIELIST, "FLUSH"); + curl_easy_setopt(handler->handle, CURLOPT_SHARE, NULL); + /* see gh issue #84 */ + curl_easy_setopt(handler->handle, CURLOPT_COOKIEJAR, NULL); } 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_body_free(&handler->response.body); @@ -2053,21 +2091,32 @@ static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *ha php_http_buffer_dtor(&handler->options.cookies); zend_hash_destroy(&handler->options.cache); +#if PHP_HTTP_CURL_VERSION(7,21,3) + if (handler->options.resolve) { + curl_slist_free_all(handler->options.resolve); + handler->options.resolve = NULL; + } +#endif + if (handler->options.headers) { curl_slist_free_all(handler->options.headers); handler->options.headers = NULL; } + if (handler->options.proxyheaders) { + curl_slist_free_all(handler->options.proxyheaders); + handler->options.proxyheaders = NULL; + } + efree(handler); } static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void *handle) { php_http_client_curl_t *curl; - TSRMLS_FETCH_FROM_CTX(h->ts); - if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle"); + if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL))) { + php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle"); return NULL; } @@ -2082,24 +2131,14 @@ static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void * static void php_http_client_curl_dtor(php_http_client_t *h) { php_http_client_curl_t *curl = h->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); -#if PHP_HTTP_HAVE_EVENT - if (curl->timeout) { - if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) { - event_del(curl->timeout); - } - efree(curl->timeout); - curl->timeout = NULL; + if (curl->ev_ops) { + curl->ev_ops->dtor(&curl->ev_ctx); + curl->ev_ops = NULL; } - if (curl->evbase) { - event_base_free(curl->evbase); - curl->evbase = NULL; - } -#endif curl->unfinished = 0; - php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); + php_resource_factory_handle_dtor(h->rf, curl->handle); efree(curl); h->ctx = NULL; @@ -2116,36 +2155,38 @@ static void queue_dtor(php_http_client_enqueue_t *e) php_http_client_curl_handler_dtor(handler); } -static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_enqueue_t *enqueue TSRMLS_DC) +static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { php_persistent_handle_factory_t *pf = NULL; php_resource_factory_t *rf = NULL; php_http_url_t *url = enqueue->request->http.info.request.url; if (!url || (!url->host && !url->path)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL"); + php_error_docref(NULL, E_WARNING, "Cannot request empty URL"); return NULL; } /* only if the client itself is setup for persistence */ if (php_resource_factory_is_persistent(h->rf)) { + zend_string *id; char *id_str = NULL; size_t id_len; int port = url->port ? url->port : 80; - zval **zport; + zval *zport; + php_persistent_handle_factory_t *phf = h->rf->data; - if (SUCCESS == zend_hash_find(enqueue->options, ZEND_STRS("port"), (void *) &zport)) { - zval *zcpy = php_http_ztyp(IS_LONG, *zport); + if ((zport = zend_hash_str_find(enqueue->options, ZEND_STRL("port")))) { + zend_long lport = zval_get_long(zport); - if (Z_LVAL_P(zcpy)) { - port = Z_LVAL_P(zcpy); + if (lport > 0) { + port = lport; } - zval_ptr_dtor(&zcpy); } - id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), port); - pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC); - efree(id_str); + id_len = spprintf(&id_str, 0, "%.*s:%s:%d", (int) phf->ident->len, phf->ident->val, STR_PTR(url->host), port); + id = php_http_cs2zs(id_str, id_len); + pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, NULL); + zend_string_release(id); } if (pf) { @@ -2164,9 +2205,8 @@ static ZEND_RESULT_CODE php_http_client_curl_enqueue(php_http_client_t *h, php_h php_http_client_curl_handler_t *handler; php_http_client_progress_state_t *progress; php_resource_factory_t *rf; - TSRMLS_FETCH_FROM_CTX(h->ts); - rf = create_rf(h, enqueue TSRMLS_CC); + rf = create_rf(h, enqueue); if (!rf) { return FAILURE; } @@ -2185,21 +2225,22 @@ static ZEND_RESULT_CODE php_http_client_curl_enqueue(php_http_client_t *h, php_h enqueue->opaque = handler; enqueue->dtor = queue_dtor; - if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, handler->handle))) { - zend_llist_add_element(&h->requests, enqueue); - ++curl->unfinished; + if (CURLM_OK != (rs = curl_multi_add_handle(curl->handle->multi, handler->handle))) { + php_http_client_curl_handler_dtor(handler); + php_error_docref(NULL, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); + return FAILURE; + } - if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { - progress->info = "start"; - h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); - progress->started = 1; - } + zend_llist_add_element(&h->requests, enqueue); + ++curl->unfinished; - return SUCCESS; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); - return FAILURE; + if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { + progress->info = "start"; + h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); + progress->started = 1; } + + return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) @@ -2207,14 +2248,18 @@ static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_h CURLMcode rs; php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler = enqueue->opaque; - TSRMLS_FETCH_FROM_CTX(h->ts); + + if (h->callback.depth && !CG(unclean_shutdown)) { + php_error_docref(NULL, E_WARNING, "Could not dequeue request while executing callbacks"); + return FAILURE; + } php_http_client_curl_handler_clear(handler); - if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, handler->handle))) { + if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) { zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); return SUCCESS; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs)); + php_error_docref(NULL, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs)); } return FAILURE; @@ -2230,18 +2275,7 @@ static void php_http_client_curl_reset(php_http_client_t *h) } } -static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout) -{ - if ((CURLM_OK == curl_multi_timeout(curl->handle, &max_tout)) && (max_tout > 0)) { - timeout->tv_sec = max_tout / 1000; - timeout->tv_usec = (max_tout % 1000) * 1000; - } else { - timeout->tv_sec = 0; - timeout->tv_usec = 1000; - } -} - -#ifdef PHP_WIN32 +#if PHP_WIN32 # define SELECT_ERROR SOCKET_ERROR #else # define SELECT_ERROR -1 @@ -2254,28 +2288,15 @@ static ZEND_RESULT_CODE php_http_client_curl_wait(php_http_client_t *h, struct t struct timeval timeout; php_http_client_curl_t *curl = h->ctx; -#if PHP_HTTP_HAVE_EVENT - if (curl->useevents) { - if (!event_initialized(curl->timeout)) { - event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, h); - } else if (custom_timeout && timerisset(custom_timeout)) { - event_add(curl->timeout, custom_timeout); - } else if (!event_pending(curl->timeout, EV_TIMEOUT, NULL)) { - php_http_client_curl_get_timeout(curl, 1000, &timeout); - event_add(curl->timeout, &timeout); - } - - event_base_loop(curl->evbase, EVLOOP_ONCE); - - return SUCCESS; + if (curl->ev_ops) { + return curl->ev_ops->wait(curl->ev_ctx, custom_timeout); } -#endif FD_ZERO(&R); FD_ZERO(&W); FD_ZERO(&E); - if (CURLM_OK == curl_multi_fdset(curl->handle, &R, &W, &E, &MAX)) { + if (CURLM_OK == curl_multi_fdset(curl->handle->multi, &R, &W, &E, &MAX)) { if (custom_timeout && timerisset(custom_timeout)) { timeout = *custom_timeout; } else { @@ -2296,51 +2317,35 @@ static int php_http_client_curl_once(php_http_client_t *h) { php_http_client_curl_t *curl = h->ctx; -#if PHP_HTTP_HAVE_EVENT - if (curl->useevents) { - event_base_loop(curl->evbase, EVLOOP_NONBLOCK); - } else -#endif - while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle, &curl->unfinished)); + if (!h->callback.depth) { + if (curl->ev_ops) { + curl->ev_ops->once(curl->ev_ctx); + } else { + while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle->multi, &curl->unfinished)); + } - php_http_curlm_responsehandler(h); + php_http_client_curl_responsehandler(h); + } return curl->unfinished; - } static ZEND_RESULT_CODE php_http_client_curl_exec(php_http_client_t *h) { -#if PHP_HTTP_HAVE_EVENT php_http_client_curl_t *curl = h->ctx; -#endif - TSRMLS_FETCH_FROM_CTX(h->ts); - -#if PHP_HTTP_HAVE_EVENT - if (curl->useevents) { - php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h); - do { - int ev_rc = event_base_dispatch(curl->evbase); -#if DBG_EVENTS - fprintf(stderr, "%c", "X.0"[ev_rc+1]); -#endif + if (!h->callback.depth) { + if (curl->ev_ops) { + return curl->ev_ops->exec(curl->ev_ctx); + } - if (ev_rc < 0) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error in event_base_dispatch()"); - return FAILURE; - } - } while (curl->unfinished && !EG(exception)); - } else -#endif - { while (php_http_client_curl_once(h) && !EG(exception)) { if (SUCCESS != php_http_client_curl_wait(h, NULL)) { -#ifdef PHP_WIN32 +#if PHP_WIN32 /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError()); + php_error_docref(NULL, E_WARNING, "WinSock error: %d", WSAGetLastError()); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); #endif return FAILURE; } @@ -2360,14 +2365,16 @@ static ZEND_RESULT_CODE php_http_client_curl_setopt(php_http_client_t *h, php_ht break; case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING: - if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { + if (CURLM_OK != curl_multi_setopt(curl->handle->multi, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { return FAILURE; } break; case PHP_HTTP_CLIENT_OPT_USE_EVENTS: -#if PHP_HTTP_HAVE_EVENT - return php_http_curlm_use_eventloop(h, *(zend_bool *) arg); +#if PHP_HTTP_HAVE_LIBEVENT + return php_http_curlm_use_eventloop(h, (*(zend_bool *) arg) + ? php_http_client_curl_event_ops_get() + : NULL, NULL); break; #endif @@ -2377,34 +2384,31 @@ static ZEND_RESULT_CODE php_http_client_curl_setopt(php_http_client_t *h, php_ht return SUCCESS; } -static int apply_available_options(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +static int apply_available_options(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key) { - php_http_option_t *opt = pDest; + php_http_option_t *opt = Z_PTR_P(pDest); HashTable *ht; - zval *entry; + zval entry; int c; ht = va_arg(args, HashTable*); - MAKE_STD_ZVAL(entry); - if ((c = zend_hash_num_elements(&opt->suboptions.options))) { - array_init_size(entry, c); - zend_hash_apply_with_arguments(&opt->suboptions.options TSRMLS_CC, apply_available_options, 1, Z_ARRVAL_P(entry)); + array_init_size(&entry, c); + zend_hash_apply_with_arguments(&opt->suboptions.options, apply_available_options, 1, Z_ARRVAL(entry)); } else { /* catch deliberate NULL options */ if (Z_TYPE(opt->defval) == IS_STRING && !Z_STRVAL(opt->defval)) { - ZVAL_NULL(entry); + ZVAL_NULL(&entry); } else { - ZVAL_COPY_VALUE(entry, &opt->defval); - zval_copy_ctor(entry); + ZVAL_ZVAL(&entry, &opt->defval, 1, 0); } } - if (hash_key->nKeyLength) { - zend_hash_quick_update(ht, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &entry, sizeof(zval *), NULL); + if (hash_key->key) { + zend_hash_update(ht, hash_key->key, &entry); } else { - zend_hash_index_update(ht, hash_key->h, (void *) &entry, sizeof(zval *), NULL); + zend_hash_index_update(ht, hash_key->h, &entry); } return ZEND_HASH_APPLY_KEEP; @@ -2413,7 +2417,6 @@ static int apply_available_options(void *pDest TSRMLS_DC, int num_args, va_list static ZEND_RESULT_CODE php_http_client_curl_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void **res) { php_http_client_enqueue_t *enqueue; - TSRMLS_FETCH_FROM_CTX(h->ts); switch (opt) { case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO: @@ -2435,11 +2438,11 @@ static ZEND_RESULT_CODE php_http_client_curl_getopt(php_http_client_t *h, php_ht break; case PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS: - zend_hash_apply_with_arguments(&php_http_curle_options.options TSRMLS_CC, apply_available_options, 1, *(HashTable **) res); + zend_hash_apply_with_arguments(&php_http_curle_options.options, apply_available_options, 1, *(HashTable **) res); break; case PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION: - zend_hash_apply_with_arguments(&php_http_curlm_options.options TSRMLS_CC, apply_available_options, 1, *(HashTable **) res); + zend_hash_apply_with_arguments(&php_http_curlm_options.options, apply_available_options, 1, *(HashTable **) res); break; default: @@ -2469,22 +2472,33 @@ php_http_client_ops_t *php_http_client_curl_get_ops(void) return &php_http_client_curl_ops; } +#define REGISTER_NS_STRING_OR_NULL_CONSTANT(ns, name, str, flags) \ + do { \ + if ((str) != NULL) { \ + REGISTER_NS_STRING_CONSTANT(ns, name, str, flags); \ + } else { \ + REGISTER_NS_NULL_CONSTANT(ns, name, flags); \ + } \ + } while (0) + PHP_MINIT_FUNCTION(http_client_curl) { + curl_version_info_data *info; php_http_options_t *options; - php_http_client_driver_t driver = { - ZEND_STRL("curl"), - &php_http_client_curl_ops - }; - if (SUCCESS != php_http_client_driver_add(&driver)) { + 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; } @@ -2492,13 +2506,69 @@ PHP_MINIT_FUNCTION(http_client_curl) options->getter = php_http_curle_get_option; options->setter = php_http_curle_set_option; - php_http_curle_options_init(options TSRMLS_CC); + php_http_curle_options_init(options); } if ((options = php_http_options_init(&php_http_curlm_options, 1))) { options->getter = php_http_option_get; options->setter = php_http_curlm_set_option; - php_http_curlm_options_init(options TSRMLS_CC); + php_http_curlm_options_init(options); + } + + if ((info = curl_version_info(CURLVERSION_NOW))) { + /* + * Feature constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "FEATURES", info->features, CONST_CS|CONST_PERSISTENT); + + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "IPV6", CURL_VERSION_IPV6, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "KERBEROS4", CURL_VERSION_KERBEROS4, CONST_CS|CONST_PERSISTENT); +#if PHP_HTTP_CURL_VERSION(7,40,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "KERBEROS5", CURL_VERSION_KERBEROS5, CONST_CS|CONST_PERSISTENT); +#endif + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SSL", CURL_VERSION_SSL, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "LIBZ", CURL_VERSION_LIBZ, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "NTLM", CURL_VERSION_NTLM, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "GSSNEGOTIATE", CURL_VERSION_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "ASYNCHDNS", CURL_VERSION_ASYNCHDNS, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SPNEGO", CURL_VERSION_SPNEGO, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "LARGEFILE", CURL_VERSION_LARGEFILE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "IDN", CURL_VERSION_IDN, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SSPI", CURL_VERSION_SSPI, CONST_CS|CONST_PERSISTENT); +#if PHP_HTTP_CURL_VERSION(7,38,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "GSSAPI", CURL_VERSION_GSSAPI, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,21,4) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "TLSAUTH_SRP", CURL_VERSION_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,22,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "NTLM_WB", CURL_VERSION_NTLM_WB, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,33,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "HTTP2", CURL_VERSION_HTTP2, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,40,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,47,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "PSL", CURL_VERSION_PSL, CONST_CS|CONST_PERSISTENT); +#endif + + /* + * Version constants + */ + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl", "VERSIONS", curl_version(), CONST_CS|CONST_PERSISTENT); +#if CURLVERSION_NOW >= 0 + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "CURL", (char *) info->version, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "SSL", (char *) info->ssl_version, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "LIBZ", (char *) info->libz_version, CONST_CS|CONST_PERSISTENT); +# if CURLVERSION_NOW >= 1 + REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ARES", (char *) info->ares, CONST_CS|CONST_PERSISTENT); +# if CURLVERSION_NOW >= 2 + REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "IDN", (char *) info->libidn, CONST_CS|CONST_PERSISTENT); +# endif +# endif +#endif } /* @@ -2508,6 +2578,9 @@ PHP_MINIT_FUNCTION(http_client_curl) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,33,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2_0", CURL_HTTP_VERSION_2_0, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,47,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2TLS", CURL_HTTP_VERSION_2TLS, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT); @@ -2523,7 +2596,7 @@ PHP_MINIT_FUNCTION(http_client_curl) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3, CONST_CS|CONST_PERSISTENT); REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT, CONST_CS|CONST_PERSISTENT); -#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP) +#if PHP_HTTP_CURL_VERSION(7,21,4) && PHP_HTTP_HAVE_LIBCURL_TLSAUTH_TYPE REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "TLSAUTH_SRP", CURL_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT); #endif @@ -2578,8 +2651,11 @@ PHP_MINIT_FUNCTION(http_client_curl) PHP_MSHUTDOWN_FUNCTION(http_client_curl) { - php_persistent_handle_cleanup(ZEND_STRL("http\\Client\\Curl"), NULL, 0 TSRMLS_CC); - php_persistent_handle_cleanup(ZEND_STRL("http\\Client\\Curl\\Request"), NULL, 0 TSRMLS_CC); + php_persistent_handle_cleanup(PHP_HTTP_G->client.curl.driver.client_name, NULL); + php_persistent_handle_cleanup(PHP_HTTP_G->client.curl.driver.request_name, NULL); + zend_string_release(PHP_HTTP_G->client.curl.driver.client_name); + zend_string_release(PHP_HTTP_G->client.curl.driver.request_name); + zend_string_release(PHP_HTTP_G->client.curl.driver.driver_name); php_http_options_dtor(&php_http_curle_options); php_http_options_dtor(&php_http_curlm_options); @@ -2587,7 +2663,7 @@ PHP_MSHUTDOWN_FUNCTION(http_client_curl) return SUCCESS; } -#endif /* PHP_HTTP_HAVE_CURL */ +#endif /* PHP_HTTP_HAVE_LIBCURL */ /* * Local variables: