X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=src%2Fphp_http_client_curl.c;h=915b8fc31f506ccf1aec46abd6a343bd5d7cd30d;hp=b4f2d04db75655a1bbf492f6a7f528e5c662f4e4;hb=HEAD;hpb=e4094d44990e46a0adcc2138eca4053156cd2201 diff --git a/src/php_http_client_curl.c b/src/php_http_client_curl.c index b4f2d04..4decc7a 100644 --- a/src/php_http_client_curl.c +++ b/src/php_http_client_curl.c @@ -17,6 +17,8 @@ #if PHP_HTTP_HAVE_LIBCURL +#define DEBUG_COOKIES 0 + #if PHP_HTTP_HAVE_LIBCURL_OPENSSL # include #endif @@ -311,14 +313,14 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, return 0; } -static int php_http_curle_header_callback(char *data, size_t n, size_t l, void *arg) +static size_t php_http_curle_header_callback(char *data, size_t n, size_t l, void *arg) { php_http_client_curl_handler_t *h = arg; return php_http_buffer_append(&h->response.headers, data, n * l); } -static int php_http_curle_body_callback(char *data, size_t n, size_t l, void *arg) +static size_t php_http_curle_body_callback(char *data, size_t n, size_t l, void *arg) { php_http_client_curl_handler_t *h = arg; @@ -330,6 +332,7 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) char *c = NULL; long l = 0; double d = 0; + curl_off_t o = 0; struct curl_slist *s = NULL, *p = NULL; zval tmp; @@ -364,18 +367,34 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "size_upload", lenof("size_upload"), &tmp); } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "size_upload_t", lenof("size_upload_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_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_SIZE_DOWNLOAD_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "size_download_t", lenof("size_download_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_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_DOWNLOAD_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "speed_download_t", lenof("speed_download_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_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_SPEED_UPLOAD_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "speed_upload_t", lenof("speed_upload_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "header_size", lenof("header_size"), &tmp); @@ -392,14 +411,26 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "filetime", lenof("filetime"), &tmp); } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "filetime_t", lenof("filetime_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_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_DOWNLOAD_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "content_length_download_t", lenof("content_length_download_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_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_CONTENT_LENGTH_UPLOAD_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "content_length_upload_t", lenof("content_length_upload_t"), &tmp); + } if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "starttransfer_time", lenof("starttransfer_time"), &tmp); @@ -509,6 +540,40 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "scheme", lenof("scheme"), &tmp); } +#endif + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "total_time_t", lenof("total_time_t"), &tmp); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "namelookup_time_t", lenof("namelookup_time_t"), &tmp); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "connect_time_t", lenof("connect_time_t"), &tmp); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "pretransfer_time_t", lenof("pretransfer_time_t"), &tmp); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "starttransfer_time_t", lenof("starttransfer_time_t"), &tmp); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "redirect_time_t", lenof("redirect_time_t"), &tmp); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME_T, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "appconnect_time_t", lenof("appconnect_time_t"), &tmp); + } +#if PHP_HTTP_CURL_VERSION(7,66,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RETRY_AFTER, &o)) { + ZVAL_LONG(&tmp, o); + zend_hash_str_update(info, "retry_after", lenof("retry_after"), &tmp); + } #endif #if PHP_HTTP_CURL_VERSION(7,72,0) if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_METHOD, &c)) { @@ -522,6 +587,24 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) zend_hash_str_update(info, "proxy_error", lenof("proxy_error"), &tmp); } #endif +#if PHP_HTTP_CURL_VERSION(7,76,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REFERER, &c)) { + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "referer", lenof("referer"), &tmp); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,84,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CAINFO, &c)) { + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "cainfo", lenof("cainfo"), &tmp); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,84,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CAPATH, &c)) { + ZVAL_STRING(&tmp, STR_PTR(c)); + zend_hash_str_update(info, "capath", lenof("capath"), &tmp); + } +#endif /* END::CURLINFO */ @@ -621,8 +704,9 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info) #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,39,0) && PHP_HTTP_HAVE_LIBCURL_GSKIT) || \ (PHP_HTTP_CURL_VERSION(7,42,0) && PHP_HTTP_HAVE_LIBCURL_GNUTLS) || \ - (PHP_HTTP_CURL_VERSION(7,39,0) && PHP_HTTP_HAVE_LIBCURL_GSKIT) + (PHP_HTTP_CURL_VERSION(7,79,0) && PHP_HTTP_HAVE_LIBCURL_SECURETRANSPORT) { int i; zval ci_array, subarray; @@ -805,6 +889,7 @@ static php_http_options_t php_http_curle_options, php_http_curlm_options; #define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN 0x0001 #define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR 0x0002 #define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS 0x0004 +#define PHP_HTTP_CURLE_OPTION_IGNORE_RC 0x0008 static ZEND_RESULT_CODE php_http_curle_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata) { @@ -826,6 +911,9 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookiesession(php_http_option_ return FAILURE; } if (Z_TYPE_P(val) == IS_TRUE) { +#if DEBUG_COOKIES + fprintf(stderr, "CURLOPT_COOKIELIST: SESS\n"); +#endif if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIELIST, "SESS")) { return FAILURE; } @@ -848,9 +936,19 @@ static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t } else { storage->cookiestore = NULL; } - if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore) - || CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore) - ) { + +#if DEBUG_COOKIES + fprintf(stderr, "CURLOPT_COOKIEFILE: %s\n", storage->cookiestore); +#endif + // does NOT enable ch->data.cookies until transfer; adds to ch->stsate.cookielist + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore ? storage->cookiestore : "")) { + return FAILURE; + } +#if DEBUG_COOKIES + fprintf(stderr, "CURLOPT_COOKIEJAR: %s\n", storage->cookiestore); +#endif + // enables ch->data.cookies + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)) { return FAILURE; } @@ -942,6 +1040,21 @@ static ZEND_RESULT_CODE php_http_curle_option_set_lastmodified(php_http_option_t return SUCCESS; } +#if PHP_HTTP_CURL_VERSION(7,64,1) +static ZEND_RESULT_CODE php_http_curle_option_set_altsvc_ctrl(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (Z_LVAL_P(val)) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ALTSVC_CTRL, Z_LVAL_P(val))) { + return FAILURE; + } + } + return SUCCESS; +} +#endif + static ZEND_RESULT_CODE php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) { php_http_client_curl_handler_t *curl = userdata; @@ -1164,8 +1277,10 @@ 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_NONE: + break; case CURL_TLSAUTH_SRP: - if (CURLE_OK == curl_easy_setopt(ch, opt->option, PHP_HTTP_LIBCURL_TLSAUTH_SRP)) { + if (CURLE_OK == curl_easy_setopt(ch, opt->option, "SRP")) { return SUCCESS; } /* no break */ @@ -1173,7 +1288,7 @@ static ZEND_RESULT_CODE php_http_curle_option_set_ssl_tlsauthtype(php_http_optio return FAILURE; } } - if (CURLE_OK != curl_easy_setopt(ch, opt->option, PHP_HTTP_LIBCURL_TLSAUTH_DEF)) { + if (CURLE_OK != curl_easy_setopt(ch, opt->option, "NONE")) { return FAILURE; } return SUCCESS; @@ -1269,6 +1384,9 @@ static void php_http_curle_options_init(php_http_options_t *registry) #if PHP_HTTP_CURL_VERSION(7,60,0) php_http_option_register(registry, ZEND_STRL("dns_shuffle_addresses"), CURLOPT_DNS_SHUFFLE_ADDRESSES, _IS_BOOL); #endif +#if PHP_HTTP_CURL_VERSION(7,62,0) + php_http_option_register(registry, ZEND_STRL("doh_url"), CURLOPT_DOH_URL, IS_STRING); +#endif /* limits */ @@ -1288,6 +1406,11 @@ static void php_http_curle_options_init(php_http_options_t *registry) */ 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); +#if PHP_HTTP_CURL_VERSION(7,65,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("maxage_conn"), CURLOPT_MAXAGE_CONN, IS_LONG))) { + ZVAL_LONG(&opt->defval, 118); + } +#endif /* outgoing interface */ php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING); @@ -1316,6 +1439,14 @@ static void php_http_curle_options_init(php_http_options_t *registry) opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } #endif +#if PHP_HTTP_CURL_VERSION(7,61,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("xoauth2_bearer"), CURLOPT_XOAUTH2_BEARER, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } +#endif +#if PHP_HTTP_CURL_VERSION(7,75,0) + php_http_option_register(registry, ZEND_STRL("aws_sigv4"), CURLOPT_AWS_SIGV4, IS_STRING); +#endif /* redirects */ if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) { @@ -1401,6 +1532,9 @@ static void php_http_curle_options_init(php_http_options_t *registry) /* http protocol version */ php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG); +#if PHP_HTTP_CURL_VERSION(7,64,0) + php_http_option_register(registry, ZEND_STRL("http09_allowed"), CURLOPT_HTTP09_ALLOWED, _IS_BOOL); +#endif /* timeouts */ if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) { @@ -1429,7 +1563,10 @@ static void php_http_curle_options_init(php_http_options_t *registry) } #endif #if PHP_HTTP_CURL_VERSION(7,49,0) +# if defined(linux) || defined(__APPLE__) + /* CURLOPT_TCP_FASTOPEN is not supported (yet) on Windows */ php_http_option_register(registry, ZEND_STRL("tcp_fastopen"), CURLOPT_TCP_FASTOPEN, _IS_BOOL); +# endif #endif /* ssl */ @@ -1541,9 +1678,11 @@ static void php_http_curle_options_init(php_http_options_t *registry) } #endif #if PHP_HTTP_CURL_VERSION(7,42,0) && (PHP_HTTP_HAVE_LIBCURL_NSS || PHP_HTTP_HAVE_LIBCURL_SECURETRANSPORT) - php_http_option_register(ssl_registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, _IS_BOOL); + if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, _IS_BOOL))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_IGNORE_RC; + } #endif -#if PHP_HTTP_CURL_VERSION(7,61,0) +#if PHP_HTTP_CURL_VERSION(7,61,0) && PHP_HTTP_HAVE_LIBCURL_TLS13_CIPHERS if ((opt = php_http_option_register(ssl_registry, ZEND_STRL("tls13_ciphers"), CURLOPT_TLS13_CIPHERS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } @@ -1583,6 +1722,12 @@ static void php_http_curle_options_init(php_http_options_t *registry) opt->setter = php_http_curle_option_set_ssl_verifyhost; } php_http_option_register(proxy_registry, ZEND_STRL("cipher_list"), CURLOPT_PROXY_SSL_CIPHER_LIST, IS_STRING); +# if PHP_HTTP_CURL_VERSION(7,71,0) + if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("issuercert"), CURLOPT_PROXY_ISSUERCERT, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +# endif # if PHP_HTTP_HAVE_LIBCURL_OPENSSL if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("crlfile"), CURLOPT_PROXY_CRLFILE, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; @@ -1626,15 +1771,41 @@ static void php_http_curle_options_init(php_http_options_t *registry) opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; } # endif -# if PHP_HTTP_CURL_VERSION(7,61,0) +# if PHP_HTTP_CURL_VERSION(7,61,0) && PHP_HTTP_HAVE_LIBCURL_TLS13_CIPHERS if ((opt = php_http_option_register(proxy_registry, ZEND_STRL("tls13_ciphers"), CURLOPT_PROXY_TLS13_CIPHERS, IS_STRING))) { opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; } # endif } #endif + } +#if PHP_HTTP_CURL_VERSION(7,64,1) +# if !PHP_HTTP_HAVE_LIBCURL_ALT_SVC + if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_ALTSVC)) { +# endif + if ((opt = php_http_option_register(registry, ZEND_STRL("altsvc_ctrl"), CURLOPT_ALTSVC_CTRL, IS_LONG))) { + opt->setter = php_http_curle_option_set_altsvc_ctrl; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("altsvc"), CURLOPT_ALTSVC, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +# if !PHP_HTTP_HAVE_LIBCURL_ALT_SVC } +# endif +#endif +#if PHP_HTTP_CURL_VERSION(7,74,0) +# if !PHP_HTTP_HAVE_LIBCURL_HSTS + if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_HSTS)) { +# endif + php_http_option_register(registry, ZEND_STRL("hsts_ctrl"), CURLOPT_HSTS_CTRL, IS_LONG); + if ((opt = php_http_option_register(registry, ZEND_STRL("hsts"), CURLOPT_HSTS, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + } +# if !PHP_HTTP_HAVE_LIBCURL_HSTS + } +# endif +#endif } static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *options, void *userdata) @@ -1732,12 +1903,16 @@ static ZEND_RESULT_CODE php_http_curle_set_option(php_http_option_t *opt, zval * break; } if (rv != SUCCESS) { - php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc)); + if (opt->flags & PHP_HTTP_CURLE_OPTION_IGNORE_RC) { + rv = SUCCESS; + } else { + php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc)); + } } return rv; } -#if PHP_HTTP_CURL_VERSION(7,30,0) +#if PHP_HTTP_CURL_VERSION(7,30,0) && !PHP_HTTP_CURL_VERSION(7,62,0) static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; @@ -1839,7 +2014,7 @@ static ZEND_RESULT_CODE php_http_curlm_option_set_share_cookies(php_http_option_ return SUCCESS; } -#if PHP_HTTP_CURL_VERSION(7,23,0) +#if PHP_HTTP_HAVE_LIBCURL_SHARE_SSL 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; @@ -1872,38 +2047,38 @@ static void php_http_curlm_options_init(php_http_options_t *registry) /* set max number of connections to a single host */ #if PHP_HTTP_CURL_VERSION(7,30,0) php_http_option_register(registry, ZEND_STRL("max_host_connections"), CURLMOPT_MAX_HOST_CONNECTIONS, IS_LONG); -#endif - /* maximum number of requests in a pipeline */ -#if PHP_HTTP_CURL_VERSION(7,30,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("max_pipeline_length"), CURLMOPT_MAX_PIPELINE_LENGTH, IS_LONG))) { - ZVAL_LONG(&opt->defval, 5); - } #endif /* max simultaneously open connections */ #if PHP_HTTP_CURL_VERSION(7,30,0) php_http_option_register(registry, ZEND_STRL("max_total_connections"), CURLMOPT_MAX_TOTAL_CONNECTIONS, IS_LONG); #endif +#if PHP_HTTP_CURL_VERSION(7,67,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("max_concurrent_streams"), CURLMOPT_MAX_CONCURRENT_STREAMS, IS_LONG))) { + ZVAL_LONG(&opt->defval, 100); + } +#endif + +#if !PHP_HTTP_CURL_VERSION(7,62,0) /* enable/disable HTTP pipelining */ php_http_option_register(registry, ZEND_STRL("pipelining"), CURLMOPT_PIPELINING, _IS_BOOL); +# if PHP_HTTP_CURL_VERSION(7,30,0) + /* maximum number of requests in a pipeline */ + if ((opt = php_http_option_register(registry, ZEND_STRL("max_pipeline_length"), CURLMOPT_MAX_PIPELINE_LENGTH, IS_LONG))) { + ZVAL_LONG(&opt->defval, 5); + } /* 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); -#endif /* size threshold for pipelining penalty */ -#if PHP_HTTP_CURL_VERSION(7,30,0) php_http_option_register(registry, ZEND_STRL("content_length_penalty_size"), CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, IS_LONG); -#endif /* pipelining server blacklist */ -#if PHP_HTTP_CURL_VERSION(7,30,0) if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_server_bl"), CURLMOPT_PIPELINING_SERVER_BL, IS_ARRAY))) { opt->setter = php_http_curlm_option_set_pipelining_bl; } -#endif /* pipelining host blacklist */ -#if PHP_HTTP_CURL_VERSION(7,30,0) if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_site_bl"), CURLMOPT_PIPELINING_SITE_BL, IS_ARRAY))) { opt->setter = php_http_curlm_option_set_pipelining_bl; } +# endif #endif /* events */ if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, 0))) { @@ -1914,7 +2089,7 @@ static void php_http_curlm_options_init(php_http_options_t *registry) opt->setter = php_http_curlm_option_set_share_cookies; ZVAL_TRUE(&opt->defval); } -#if PHP_HTTP_CURL_VERSION(7,23,0) +#if PHP_HTTP_HAVE_LIBCURL_SHARE_SSL 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); @@ -1972,9 +2147,10 @@ static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval * /* client ops */ -static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_handler_t *curl) +static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_handler_t *handler) { - CURL *ch = curl->handle; + php_http_client_curl_t *curl = handler->client->ctx; + CURL *ch = handler->handle; php_http_curle_storage_t *st; if ((st = php_http_curle_get_storage(ch))) { @@ -2003,27 +2179,61 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_ #endif #if PHP_HTTP_CURL_VERSION(7,21,3) - if (curl->options.resolve) { - curl_slist_free_all(curl->options.resolve); - curl->options.resolve = NULL; + if (handler->options.resolve) { + curl_slist_free_all(handler->options.resolve); + handler->options.resolve = NULL; } #endif - curl->options.retry.count = 0; - curl->options.retry.delay = 0; - curl->options.redirects = 0; - curl->options.encode_cookies = 1; + handler->options.retry.count = 0; + handler->options.retry.delay = 0; + handler->options.redirects = 0; + handler->options.encode_cookies = 1; - if (curl->options.headers) { - curl_slist_free_all(curl->options.headers); - curl->options.headers = NULL; + if (handler->options.headers) { + curl_slist_free_all(handler->options.headers); + handler->options.headers = NULL; } - if (curl->options.proxyheaders) { - curl_slist_free_all(curl->options.proxyheaders); - curl->options.proxyheaders = NULL; + if (handler->options.proxyheaders) { + curl_slist_free_all(handler->options.proxyheaders); + handler->options.proxyheaders = NULL; } - php_http_buffer_reset(&curl->options.cookies); - php_http_buffer_reset(&curl->options.ranges); + php_http_buffer_reset(&handler->options.cookies); + php_http_buffer_reset(&handler->options.ranges); + + if (php_http_message_body_size(handler->response.body)) { + php_http_message_body_free(&handler->response.body); + handler->response.body = php_http_message_body_init(NULL, NULL); + } + php_http_buffer_reset(&handler->response.headers); + +#if ZTS + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); +#endif + curl_easy_setopt(ch, CURLOPT_HEADER, 0L); + curl_easy_setopt(ch, CURLOPT_FILETIME, 1L); + curl_easy_setopt(ch, CURLOPT_AUTOREFERER, 1L); + curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, php_http_curle_header_callback); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, php_http_curle_body_callback); + curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback); + curl_easy_setopt(ch, CURLOPT_READFUNCTION, php_http_curle_read_callback); + curl_easy_setopt(ch, CURLOPT_SEEKFUNCTION, php_http_curle_seek_callback); +#if PHP_HTTP_CURL_VERSION(7,32,0) + curl_easy_setopt(ch, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback); + curl_easy_setopt(ch, CURLOPT_XFERINFODATA, handler); +#else + curl_easy_setopt(ch, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback); + curl_easy_setopt(ch, CURLOPT_PROGRESSDATA, handler); +#endif + curl_easy_setopt(ch, CURLOPT_DEBUGDATA, handler); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, handler); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, handler); +#if DEBUG_COOKIES + fprintf(stderr, "CURLOPT_SHARE: %p\n", curl->handle->share); +#endif + curl_easy_setopt(ch, CURLOPT_SHARE, curl->handle->share); return SUCCESS; } @@ -2031,7 +2241,6 @@ 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; if (!(handle = php_resource_factory_handle_ctor(rf, NULL))) { @@ -2049,31 +2258,6 @@ static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_htt php_http_buffer_init(&handler->options.ranges); zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0); -#if ZTS - curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); -#endif - curl_easy_setopt(handle, CURLOPT_HEADER, 0L); - curl_easy_setopt(handle, CURLOPT_FILETIME, 1L); - curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L); - curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, php_http_curle_header_callback); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curle_body_callback); - curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback); - curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curle_read_callback); - curl_easy_setopt(handle, CURLOPT_SEEKFUNCTION, php_http_curle_seek_callback); -#if PHP_HTTP_CURL_VERSION(7,32,0) - curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback); - curl_easy_setopt(handle, CURLOPT_XFERINFODATA, handler); -#else - curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback); - curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler); -#endif - 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); return handler; @@ -2099,7 +2283,9 @@ static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_cur curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url); /* apply options */ - php_http_options_apply(&php_http_curle_options, enqueue->options, curl); + if (SUCCESS != php_http_options_apply(&php_http_curle_options, enqueue->options, curl)) { + return FAILURE; + } /* request headers */ php_http_message_update_headers(msg); @@ -2197,11 +2383,18 @@ 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); + /* see gh issue #84 */ +#if DEBUG_COOKIES + fprintf(stderr, "CURLOPT_COOKIELIST: FLUSH\n"); + fprintf(stderr, "CURLOPT_SHARE: (null)\n"); +#endif curl_easy_setopt(handler->handle, CURLOPT_COOKIELIST, "FLUSH"); curl_easy_setopt(handler->handle, CURLOPT_SHARE, NULL); - /* see gh issue #84 */ #if PHP_HTTP_CURL_VERSION(7,63,0) && !PHP_HTTP_CURL_VERSION(7,65,0) - curl_easy_setopt(handler->handle, CURLOPT_COOKIEJAR, NULL); + { + php_http_curle_storage_t *st = php_http_curle_get_storage(handler->handle); + curl_easy_setopt(handler->handle, CURLOPT_COOKIEJAR, st ? st->cookiestore : NULL); + } #endif } @@ -2282,6 +2475,17 @@ static void queue_dtor(php_http_client_enqueue_t *e) php_http_client_curl_handler_dtor(handler); } +static void retire_ch(php_persistent_handle_factory_t *f, void **handle) +{ + CURL *ch = *handle; + /* erase all cookies */ + if (ch) { + curl_easy_reset(ch); + curl_easy_setopt(ch, CURLOPT_COOKIELIST, "ALL"); + curl_easy_setopt(ch, CURLOPT_COOKIEFILE, NULL); + } +} + 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; @@ -2312,7 +2516,7 @@ static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_e 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); + pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, retire_ch); zend_string_release(id); } @@ -2370,6 +2574,43 @@ static ZEND_RESULT_CODE php_http_client_curl_enqueue(php_http_client_t *h, php_h return SUCCESS; } +static ZEND_RESULT_CODE php_http_client_curl_requeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) +{ + CURLMcode rs; + php_http_client_curl_t *curl = h->ctx; + php_http_client_curl_handler_t *handler = enqueue->opaque; + php_http_client_progress_state_t *progress; + + if (SUCCESS != php_http_client_curl_handler_reset(handler)) { + return FAILURE; + } + + if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) { + return FAILURE; + } + + if (CURLM_OK != (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) { + php_error_docref(NULL, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs)); + return FAILURE; + } + + if (CURLM_OK != (rs = curl_multi_add_handle(curl->handle->multi, handler->handle))) { + zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); + php_error_docref(NULL, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); + return FAILURE; + } + + ++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) { CURLMcode rs; @@ -2486,17 +2727,19 @@ static ZEND_RESULT_CODE php_http_client_curl_setopt(php_http_client_t *h, php_ht { php_http_client_curl_t *curl = h->ctx; + (void) curl; + switch (opt) { case PHP_HTTP_CLIENT_OPT_CONFIGURATION: return php_http_options_apply(&php_http_curlm_options, (HashTable *) arg, h); break; - +#if !PHP_HTTP_CURL_VERSION(7,62,0) case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING: if (CURLM_OK != curl_multi_setopt(curl->handle->multi, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { return FAILURE; } break; - +#endif case PHP_HTTP_CLIENT_OPT_USE_EVENTS: #if PHP_HTTP_HAVE_LIBEVENT return php_http_curlm_use_eventloop(h, (*(zend_bool *) arg) @@ -2590,6 +2833,7 @@ static php_http_client_ops_t php_http_client_curl_ops = { php_http_client_curl_once, php_http_client_curl_enqueue, php_http_client_curl_dequeue, + php_http_client_curl_requeue, php_http_client_curl_setopt, php_http_client_curl_getopt }; @@ -2599,13 +2843,13 @@ 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); \ - } \ +#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) @@ -2719,11 +2963,13 @@ PHP_MINIT_FUNCTION(http_client_curl) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ARES", info->ares, CONST_CS|CONST_PERSISTENT); REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "IDN", info->libidn, CONST_CS|CONST_PERSISTENT); tmp_ver_init(); - tmp_ptr = zend_print_ulong_to_buf(tmp_end, info->iconv_ver_num & 0xf); - tmp_end = tmp_ptr - 1; - tmp_ptr = zend_print_ulong_to_buf(tmp_end, info->iconv_ver_num >> 8); - *tmp_end = '.'; - REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ICONV", tmp_ptr, CONST_CS|CONST_PERSISTENT); + if (info->iconv_ver_num) { + tmp_ptr = zend_print_ulong_to_buf(tmp_end, info->iconv_ver_num & 0xf); + tmp_end = tmp_ptr - 1; + tmp_ptr = zend_print_ulong_to_buf(tmp_end, info->iconv_ver_num >> 8); + *tmp_end = '.'; + } + REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "ICONV", *tmp_ptr ? tmp_ptr : NULL, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,57,0) REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "BROTLI", info->brotli_version, CONST_CS|CONST_PERSISTENT); #endif @@ -2810,6 +3056,12 @@ PHP_MINIT_FUNCTION(http_client_curl) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); #if PHP_HTTP_CURL_VERSION(7,38,0) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_SPNEGO", CURLAUTH_NEGOTIATE, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,61,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BEARER", CURLAUTH_BEARER, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,75,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AWS_SIGV4", CURLAUTH_AWS_SIGV4, CONST_CS|CONST_PERSISTENT); #endif REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_ANY", CURLAUTH_ANY, CONST_CS|CONST_PERSISTENT); @@ -2837,6 +3089,16 @@ PHP_MINIT_FUNCTION(http_client_curl) REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_ALL", CURL_REDIR_POST_ALL, CONST_CS|CONST_PERSISTENT); #endif +#if PHP_HTTP_CURL_VERSION(7,64,1) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_READONLYFILE", CURLALTSVC_READONLYFILE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_H1", CURLALTSVC_H1, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_H2", CURLALTSVC_H2, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "ALTSVC_H3", CURLALTSVC_H3, CONST_CS|CONST_PERSISTENT); +#endif +#if PHP_HTTP_CURL_VERSION(7,74,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HSTS_ENABLE", CURLHSTS_ENABLE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HSTS_READONLYFILE", CURLHSTS_READONLYFILE, CONST_CS|CONST_PERSISTENT); +#endif return SUCCESS; }