add CURLOPT_ABSTRACT_UNIX_SOCKET
[m6w6/ext-http] / src / php_http_client_curl.c
index 1626b712e41496c6d98561c7ec794f067c830016..621b2f56dbffff231d2819f4934e7b14c48a3146 100644 (file)
@@ -21,7 +21,7 @@
 #      include <openssl/ssl.h>
 #endif
 #if PHP_HTTP_HAVE_LIBCURL_GNUTLS
-#      include <gnutls.h>
+#      include <gnutls/gnutls.h>
 #endif
 
 typedef struct php_http_client_curl_handler {
@@ -46,7 +46,7 @@ typedef struct php_http_client_curl_handler {
                php_http_buffer_t ranges;
 
                struct {
-                       uint count;
+                       uint32_t count;
                        double delay;
                } retry;
 
@@ -218,6 +218,7 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data,
        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)) {
@@ -234,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)) {
@@ -247,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';
@@ -321,7 +331,9 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
        long l = 0;
        double d = 0;
        struct curl_slist *s = NULL, *p = NULL;
-       zval tmp = {{0}};
+       zval tmp;
+
+       ZVAL_NULL(&tmp);
 
        /* BEGIN::CURLINFO */
        if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) {
@@ -480,6 +492,36 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                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
+#if PHP_HTTP_CURL_VERSION(7,72,0)
+       if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_METHOD, &c)) {
+               ZVAL_STRING(&tmp, STR_PTR(c));
+               zend_hash_str_update(info, "effective_method", lenof("effective_method"), &tmp);
+       }
+#endif
+#if PHP_HTTP_CURL_VERSION(7,73,0)
+       if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXY_ERROR, &l)) {
+               ZVAL_LONG(&tmp, l);
+               zend_hash_str_update(info, "proxy_error", lenof("proxy_error"), &tmp);
+       }
+#endif
 
        /* END::CURLINFO */
 
@@ -488,7 +530,11 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                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)) {
+#endif
                        char *backend;
 
                        ZVAL_NULL(&subarray);
@@ -502,15 +548,22 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                                backend = "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_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));
+                                       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;
@@ -522,11 +575,13 @@ static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
                                        char *desc;
 
                                        array_init(&subarray);
-                                       if ((desc = gnutls_session_get_desc(sess))) {
-                                               add_assoc_string_ex(&subarray, ZEND_STRL("desc"), desc);
-                                               gnutls_free(desc);
+                                       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_STRL("resumed"), gnutls_session_is_resumed(sess));
                                }
 #endif
                                break;
@@ -1148,6 +1203,9 @@ static void php_http_curle_options_init(php_http_options_t *registry)
 #if PHP_HTTP_CURL_VERSION(7,19,4)
        php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING);
 #endif
+#if PHP_HTTP_CURL_VERSION(7,55,0)
+       php_http_option_register(registry, ZEND_STRL("socks5_auth"), CURLOPT_SOCKS5_AUTH, IS_LONG);
+#endif
 
 #if PHP_HTTP_CURL_VERSION(7,37,0)
        if ((opt = php_http_option_register(registry, ZEND_STRL("proxyheader"), CURLOPT_PROXYHEADER, IS_ARRAY))) {
@@ -1168,6 +1226,11 @@ static void php_http_curle_options_init(php_http_options_t *registry)
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
                        opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
                }
+#if PHP_HTTP_CURL_VERSION(7,53,0)
+               if ((opt = php_http_option_register(registry, ZEND_STRL("abstract_unix_socket"), CURLOPT_ABSTRACT_UNIX_SOCKET, IS_STRING))) {
+                       opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+               }
+#endif
        }
 #endif
 
@@ -1357,6 +1420,9 @@ static void php_http_curle_options_init(php_http_options_t *registry)
                Z_LVAL(opt->defval) = 60;
        }
 #endif
+#if PHP_HTTP_CURL_VERSION(7,49,0)
+       php_http_option_register(registry, ZEND_STRL("tcp_fastopen"), CURLOPT_TCP_FASTOPEN, _IS_BOOL);
+#endif
 
        /* ssl */
        if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSL)) {
@@ -2033,6 +2099,10 @@ static void php_http_client_curl_handler_clear(php_http_client_curl_handler_t *h
        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 */
+#if PHP_HTTP_CURL_VERSION(7,63,0) && !PHP_HTTP_CURL_VERSION(7,65,0)
+       curl_easy_setopt(handler->handle, CURLOPT_COOKIEJAR, NULL);
+#endif
 }
 
 static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler)
@@ -2206,7 +2276,7 @@ static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_h
        php_http_client_curl_t *curl = h->ctx;
        php_http_client_curl_handler_t *handler = enqueue->opaque;
 
-       if (h->callback.depth) {
+       if (h->callback.depth && !CG(unclean_shutdown)) {
                php_error_docref(NULL, E_WARNING, "Could not dequeue request while executing callbacks");
                return FAILURE;
        }
@@ -2429,6 +2499,14 @@ 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)
 {
@@ -2509,12 +2587,12 @@ PHP_MINIT_FUNCTION(http_client_curl)
                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);
+               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_CONSTANT("http\\Client\\Curl\\Versions", "ARES", (char *) info->ares, CONST_CS|CONST_PERSISTENT);
+               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_CONSTANT("http\\Client\\Curl\\Versions", "IDN", (char *) info->libidn, CONST_CS|CONST_PERSISTENT);
+               REGISTER_NS_STRING_OR_NULL_CONSTANT("http\\Client\\Curl\\Versions", "IDN", (char *) info->libidn, CONST_CS|CONST_PERSISTENT);
 #  endif
 # endif
 #endif
@@ -2530,6 +2608,12 @@ PHP_MINIT_FUNCTION(http_client_curl)
 #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
+#if PHP_HTTP_CURL_VERSION(7,49,0)
+       REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2_PRIOR_KNOWLEDGE", CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, CONST_CS|CONST_PERSISTENT);
+#endif
+#if PHP_HTTP_CURL_VERSION(7,66,0)
+       REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_3", CURL_HTTP_VERSION_3, CONST_CS|CONST_PERSISTENT);
 #endif
        REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT);
 
@@ -2541,6 +2625,9 @@ PHP_MINIT_FUNCTION(http_client_curl)
        REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_0", CURL_SSLVERSION_TLSv1_0, CONST_CS|CONST_PERSISTENT);
        REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_1", CURL_SSLVERSION_TLSv1_1, CONST_CS|CONST_PERSISTENT);
        REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_2", CURL_SSLVERSION_TLSv1_2, CONST_CS|CONST_PERSISTENT);
+#endif
+#if PHP_HTTP_CURL_VERSION(7,52,0)
+       REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_3", CURL_SSLVERSION_TLSv1_3, CONST_CS|CONST_PERSISTENT);
 #endif
        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);
@@ -2559,6 +2646,7 @@ PHP_MINIT_FUNCTION(http_client_curl)
        /*
        * Auth Constants
        */
+       REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NONE", CURLAUTH_NONE, CONST_CS|CONST_PERSISTENT);
        REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BASIC", CURLAUTH_BASIC, CONST_CS|CONST_PERSISTENT);
        REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS|CONST_PERSISTENT);
 #if PHP_HTTP_CURL_VERSION(7,19,3)