X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=src%2Fphp_http_client_curl.c;h=1ec6624cc21a07b7e3d6957b398621b393ff989d;hp=96b0bb0ed45ecb66e74110290684e02403497acf;hb=0fa2672890a4fe58c3418670e57a511b3ea7189c;hpb=6edb136d725e73b48fdf994883e3d77372f07648 diff --git a/src/php_http_client_curl.c b/src/php_http_client_curl.c index 96b0bb0..1ec6624 100644 --- a/src/php_http_client_curl.c +++ b/src/php_http_client_curl.c @@ -12,30 +12,11 @@ #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 - #ifdef PHP_HTTP_HAVE_OPENSSL # include #endif @@ -43,18 +24,6 @@ # 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; @@ -158,12 +127,29 @@ static php_resource_factory_ops_t php_http_curle_resource_factory_ops = { static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC) { - 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) { - 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 = { @@ -196,22 +182,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); } @@ -235,6 +218,7 @@ 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) { @@ -278,20 +262,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); @@ -629,7 +636,7 @@ static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_ha 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; @@ -638,7 +645,7 @@ static void php_http_curlm_responsehandler(php_http_client_t *context) 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) { @@ -682,161 +689,27 @@ 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) +void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action) { - 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) -{ - 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; + TSRMLS_FETCH_FROM_CTX(client->ts); #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 TSRMLS_CC, 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; @@ -856,6 +729,23 @@ static ZEND_RESULT_CODE php_http_curle_option_set_ssl_verifyhost(php_http_option 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_BVAL_P(val))) { + return FAILURE; + } + if (Z_BVAL_P(val)) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIELIST, "SESS")) { + return FAILURE; + } + } + + return SUCCESS; +} + static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; @@ -875,6 +765,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t ) { return FAILURE; } + return SUCCESS; } @@ -1218,9 +1109,7 @@ static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) #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))) { @@ -1240,15 +1129,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 @@ -1321,6 +1214,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; } @@ -1396,7 +1290,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; @@ -1438,104 +1334,109 @@ 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 ((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) && (defined(PHP_HTTP_HAVE_OPENSSL) || defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_GNUTLS)) - php_http_option_register(registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, IS_BOOL); + 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; + 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); + ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0); +#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; +#ifdef PHP_HTTP_CURL_CAPATH + ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAPATH, 0); #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; - } + 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; - } + 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("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); + php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL); #endif #if PHP_HTTP_CURL_VERSION(7,36,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, IS_BOOL))) { - 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 ((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); + php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, IS_BOOL); #endif + } } } @@ -1556,7 +1457,7 @@ 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); @@ -1637,7 +1538,7 @@ 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); @@ -1676,27 +1577,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,8 +1603,59 @@ 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; + TSRMLS_FETCH_FROM_CTX(client->ts); + + if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_class_entry TSRMLS_CC)) { + ev_ops = php_http_client_curl_user_ops_get(); +#if PHP_HTTP_HAVE_EVENT + } else if (value && z_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_BVAL_P(value)) { + 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) { + TSRMLS_FETCH_FROM_CTX(client->ts); + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, 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_BVAL_P(value)) { + 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); + } - return php_http_curlm_use_eventloop(client, value && Z_BVAL_P(value)); + if (CURLSHE_OK != rc) { + TSRMLS_FETCH_FROM_CTX(client->ts); + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_share_strerror(rc)); + return FAILURE; + } + return SUCCESS; } #endif @@ -1756,10 +1705,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_BOOL(&opt->defval, 1); + } +#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_BOOL(&opt->defval, 1); + } #endif } @@ -1767,7 +1725,7 @@ 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; + CURLM *ch = curl->handle->multi; zval *orig = val; CURLMcode rc = CURLM_UNKNOWN_OPTION; ZEND_RESULT_CODE rv = SUCCESS; @@ -1786,15 +1744,18 @@ static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval * case IS_BOOL: if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) Z_BVAL_P(val)))) { rv = FAILURE; + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, 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 TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_multi_strerror(rc)); } break; default: rv = FAILURE; + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s", opt->name.s); break; } } @@ -1803,9 +1764,6 @@ static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval * 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 +1784,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 +1828,12 @@ 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"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle->multi"); return NULL; } @@ -1910,6 +1870,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); @@ -2036,6 +1997,8 @@ 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); } static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler) @@ -2067,7 +2030,7 @@ static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void * 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"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle->multi"); return NULL; } @@ -2084,19 +2047,10 @@ 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->evbase) { - event_base_free(curl->evbase); - curl->evbase = NULL; + if (curl->ev_ops) { + curl->ev_ops->dtor(&curl->ev_ctx); + curl->ev_ops = NULL; } -#endif curl->unfinished = 0; php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); @@ -2133,6 +2087,7 @@ static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_e size_t id_len; int port = url->port ? url->port : 80; 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); @@ -2143,7 +2098,7 @@ static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_e zval_ptr_dtor(&zcpy); } - id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), port); + id_len = spprintf(&id_str, 0, "%.*s:%s:%d", (int) phf->ident.len, phf->ident.str, 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); } @@ -2185,21 +2140,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 (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; - } else { + if (CURLM_OK != (rs = curl_multi_add_handle(curl->handle->multi, handler->handle))) { + php_http_client_curl_handler_dtor(handler); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); return FAILURE; } + + zend_llist_add_element(&h->requests, enqueue); + ++curl->unfinished; + + 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) @@ -2209,8 +2165,13 @@ static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_h php_http_client_curl_handler_t *handler = enqueue->opaque; TSRMLS_FETCH_FROM_CTX(h->ts); + if (h->callback.depth) { + php_error_docref(NULL TSRMLS_CC, 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 { @@ -2230,17 +2191,6 @@ 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 # define SELECT_ERROR SOCKET_ERROR #else @@ -2254,28 +2204,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,14 +2233,13 @@ 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 (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; @@ -2311,39 +2247,22 @@ static int php_http_client_curl_once(php_http_client_t *h) 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 (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)) { + while (php_http_client_curl_once(h) && !EG(exception)) { + if (SUCCESS != php_http_client_curl_wait(h, NULL)) { #ifdef 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()); + /* 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()); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); #endif - return FAILURE; - } + return FAILURE; } } @@ -2360,14 +2279,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); + return php_http_curlm_use_eventloop(h, (*(zend_bool *) arg) + ? php_http_client_curl_event_ops_get() + : NULL, NULL); break; #endif @@ -2469,8 +2390,10 @@ php_http_client_ops_t *php_http_client_curl_get_ops(void) return &php_http_client_curl_ops; } + 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"), @@ -2501,6 +2424,62 @@ PHP_MINIT_FUNCTION(http_client_curl) php_http_curlm_options_init(options TSRMLS_CC); } + 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_CONSTANT("http\\Client\\Curl\\Versions", "SSL", (char *) info->ssl_version, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "LIBZ", (char *) info->libz_version, CONST_CS|CONST_PERSISTENT); +# if CURLVERSION_NOW >= 1 + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "ARES", (char *) info->ares, CONST_CS|CONST_PERSISTENT); +# if CURLVERSION_NOW >= 2 + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "IDN", (char *) info->libidn, CONST_CS|CONST_PERSISTENT); +# endif +# endif +#endif + } + /* * HTTP Protocol Version Constants */ @@ -2508,6 +2487,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);