X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_request_api.c;h=289cac491d4ea003b0b082728dd960fd348a23b2;hp=62b66bd56f2980557440bafc3ac2428c4bfa097f;hb=cd5137b3e7cb8fe55a32b1de626127e786a86d0d;hpb=d886588e9d3193d182ee5ed82741aba45f028d52 diff --git a/http_request_api.c b/http_request_api.c index 62b66bd..289cac4 100644 --- a/http_request_api.c +++ b/http_request_api.c @@ -21,6 +21,9 @@ #include "php_http_api.h" #include "php_http_request_api.h" #include "php_http_url_api.h" +#ifdef HTTP_HAVE_PERSISTENT_HANDLES +# include "php_http_persistent_handle_api.h" +#endif #ifdef ZEND_ENGINE_2 # include "php_http_request_object.h" @@ -87,16 +90,19 @@ static struct gcry_thread_cbs http_gnutls_tsl = { PHP_MINIT_FUNCTION(http_request) { #ifdef HTTP_NEED_OPENSSL_TSL - int i, c = CRYPTO_num_locks(); - - http_openssl_tsl = malloc(c * sizeof(MUTEX_T)); - - for (i = 0; i < c; ++i) { - http_openssl_tsl[i] = tsrm_mutex_alloc(); + /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */ + if (!CRYPTO_get_id_callback()) { + int i, c = CRYPTO_num_locks(); + + http_openssl_tsl = malloc(c * sizeof(MUTEX_T)); + + for (i = 0; i < c; ++i) { + http_openssl_tsl[i] = tsrm_mutex_alloc(); + } + + CRYPTO_set_id_callback(http_openssl_thread_id); + CRYPTO_set_locking_callback(http_openssl_thread_lock); } - - CRYPTO_set_id_callback(http_openssl_thread_id); - CRYPTO_set_locking_callback(http_openssl_thread_lock); #endif #ifdef HTTP_NEED_GNUTLS_TSL gcry_control(GCRYCTL_SET_THREAD_CBS, &http_gnutls_tsl); @@ -106,6 +112,12 @@ PHP_MINIT_FUNCTION(http_request) return FAILURE; } +#ifdef HTTP_HAVE_PERSISTENT_HANDLES + if (SUCCESS != http_persistent_handle_provide("http_request", curl_easy_init, curl_easy_cleanup)) { + return FAILURE; + } +#endif + HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC); HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST); HTTP_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM); @@ -138,10 +150,6 @@ PHP_MINIT_FUNCTION(http_request) /* {{{ MSHUTDOWN */ PHP_MSHUTDOWN_FUNCTION(http_request) { -#ifdef HTTP_NEED_OPENSSL_TSL - CRYPTO_set_id_callback(http_openssl_thread_id); - CRYPTO_set_locking_callback(http_openssl_thread_lock); -#endif curl_global_cleanup(); #ifdef HTTP_NEED_OPENSSL_TSL if (http_openssl_tsl) { @@ -177,10 +185,18 @@ static int http_curl_dummy_callback(char *data, size_t n, size_t l, void *s) { r static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *); /* }}} */ +#ifdef HTTP_HAVE_PERSISTENT_HANDLES +# define HTTP_CURL_HANDLE_CTOR(ch) (SUCCESS == http_persistent_handle_acquire("http_request", &(ch))) +# define HTTP_CURL_HANDLE_DTOR(chp) http_persistent_handle_release("http_request", (chp)) +#else +# define HTTP_CURL_HANDLE_CTOR(ch) ((ch) = curl_easy_init()) +# define HTTP_CURL_HANDLE_DTOR(chp) curl_easy_cleanup(*(chp)); *(chp) = NULL +#endif + /* {{{ CURL *http_curl_init(http_request *) */ PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request) { - if (ch || (ch = curl_easy_init())) { + if (ch || HTTP_CURL_HANDLE_CTOR(ch)) { #if defined(ZTS) curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); #endif @@ -215,13 +231,12 @@ PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request) PHP_HTTP_API void _http_curl_free(CURL **ch) { if (*ch) { - /* avoid nasty segfaults with already cleaned up callbacks */ curl_easy_setopt(*ch, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(*ch, CURLOPT_PROGRESSFUNCTION, NULL); curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L); curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL); - curl_easy_cleanup(*ch); - *ch = NULL; + + HTTP_CURL_HANDLE_DTOR(ch); } } /* }}} */ @@ -309,8 +324,7 @@ PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request) TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); - if (initialized) { - curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, ""); + if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, "")) { return SUCCESS; } http_error(HE_WARNING, HTTP_E_REQUEST, "Could not enable cookies for this session"); @@ -327,16 +341,14 @@ PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int sessi HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); if (session_only) { #if HTTP_CURL_VERSION(7,15,4) - if (initialized) { - curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS"); + if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS")) { return SUCCESS; } #endif http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset session cookies (need libcurl >= v7.15.4)"); } else { #if HTTP_CURL_VERSION(7,14,1) - if (initialized) { - curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL"); + if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL")) { return SUCCESS; } #endif @@ -637,39 +649,33 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti request->_cache.headers = NULL; } if ((zoption = http_request_option(request, options, "headers", IS_ARRAY))) { - char *header_key = NULL; - ulong header_idx; + HashKey header_key = initHashKey(0); + zval **header_val; HashPosition pos; - FOREACH_KEY(pos, zoption, header_key, header_idx) { - if (header_key) { - zval **header_val; - if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(zoption), (void *) &header_val, &pos)) { - char header[1024] = {0}; - - ZVAL_ADDREF(*header_val); - convert_to_string_ex(header_val); - if (!strcasecmp(header_key, "range")) { - range_req = 1; - } - snprintf(header, lenof(header), "%s: %s", header_key, Z_STRVAL_PP(header_val)); - request->_cache.headers = curl_slist_append(request->_cache.headers, header); - zval_ptr_dtor(header_val); + FOREACH_KEYVAL(pos, zoption, header_key, header_val) { + if (header_key.type == HASH_KEY_IS_STRING) { + char header[1024]; + + ZVAL_ADDREF(*header_val); + convert_to_string_ex(header_val); + if (!strcasecmp(header_key.str, "range")) { + range_req = 1; } - - /* reset */ - header_key = NULL; + snprintf(header, sizeof(header), "%s: %s", header_key.str, Z_STRVAL_PP(header_val)); + request->_cache.headers = curl_slist_append(request->_cache.headers, header); + zval_ptr_dtor(header_val); } } } /* etag */ if ((zoption = http_request_option(request, options, "etag", IS_STRING)) && Z_STRLEN_P(zoption)) { - char match_header[1024] = {0}, *quoted_etag = NULL; + char match_header[1024], *quoted_etag = NULL; if ((Z_STRVAL_P(zoption)[0] != '"') || (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] != '"')) { spprintf("ed_etag, 0, "\"%s\"", Z_STRVAL_P(zoption)); } - snprintf(match_header, lenof(match_header), "%s: %s", range_req?"If-Match":"If-None-Match", quoted_etag?quoted_etag:Z_STRVAL_P(zoption)); + snprintf(match_header, sizeof(match_header), "%s: %s", range_req?"If-Match":"If-None-Match", quoted_etag?quoted_etag:Z_STRVAL_P(zoption)); request->_cache.headers = curl_slist_append(request->_cache.headers, match_header); STR_FREE(quoted_etag); } @@ -706,20 +712,14 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti } } else { HashPosition pos; - char *cookie_key = NULL; - ulong cookie_idx; + HashKey cookie_key = initHashKey(0); + zval **cookie_val; - FOREACH_KEY(pos, zoption, cookie_key, cookie_idx) { - if (cookie_key) { - zval **cookie_val; - if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(zoption), (void *) &cookie_val, &pos)) { - zval *val = zval_copy(IS_STRING, *cookie_val); - phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key, Z_STRVAL_P(val)); - zval_free(&val); - } - - /* reset */ - cookie_key = NULL; + FOREACH_KEYVAL(pos, zoption, cookie_key, cookie_val) { + if (cookie_key.type == HASH_KEY_IS_STRING) { + zval *val = zval_copy(IS_STRING, *cookie_val); + phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(val)); + zval_free(&val); } } @@ -755,25 +755,34 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, Z_LVAL_P(zoption)); } +#if HTTP_CURL_VERSION(7,16,2) + /* timeout, defaults to 0 */ + if ((zoption = http_request_option(request, options, "timeout", IS_DOUBLE))) { + HTTP_CURL_OPT(CURLOPT_TIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000)); + } + /* connecttimeout, defaults to 0 */ + if ((zoption = http_request_option(request, options, "connecttimeout", IS_DOUBLE))) { + HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000)); + } +#else /* timeout, defaults to 0 */ if ((zoption = http_request_option(request, options, "timeout", IS_LONG))) { HTTP_CURL_OPT(CURLOPT_TIMEOUT, Z_LVAL_P(zoption)); } - /* connecttimeout, defaults to 0 */ if ((zoption = http_request_option(request, options, "connecttimeout", IS_LONG))) { HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, Z_LVAL_P(zoption)); } +#endif /* ssl */ if ((zoption = http_request_option(request, options, "ssl", IS_ARRAY))) { - ulong idx; - char *key = NULL; + HashKey key = initHashKey(0); zval **param; HashPosition pos; - FOREACH_KEYVAL(pos, zoption, key, idx, param) { - if (key) { + FOREACH_KEYVAL(pos, zoption, key, param) { + if (key.type == HASH_KEY_IS_STRING) { HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT, 0, 1); HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE, 0, 0); HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD, 0, 0); @@ -793,9 +802,6 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti HTTP_CURL_OPT_STRING(CURLOPT_CAPATH, -3, 1); HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE, -3, 1); HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET, -3, 1); - - /* reset key */ - key = NULL; } } } @@ -967,46 +973,44 @@ static int http_curl_raw_callback(CURL *ch, curl_infotype type, char *data, size { http_request *request = (http_request *) ctx; +#define EMPTY_HEADER(d, l) (!l || (l == 1 && d[0] == '\n') || (l == 2 && d[0] == '\r' && d[1] == '\n')) switch (type) { case CURLINFO_DATA_IN: if (request->conv.last_type == CURLINFO_HEADER_IN) { phpstr_appends(&request->conv.response, HTTP_CRLF); } - case CURLINFO_HEADER_IN: phpstr_append(&request->conv.response, data, length); break; - case CURLINFO_DATA_OUT: - if (request->conv.last_type == CURLINFO_HEADER_OUT) { - phpstr_appends(&request->conv.request, HTTP_CRLF); + case CURLINFO_HEADER_IN: + if (!EMPTY_HEADER(data, length)) { + phpstr_append(&request->conv.response, data, length); } + break; + case CURLINFO_DATA_OUT: case CURLINFO_HEADER_OUT: phpstr_append(&request->conv.request, data, length); break; default: + break; + } + #if 0 - fprintf(stderr, "## ", type); - if (!type) { - fprintf(stderr, "%s", data); - } else { - ulong i; - for (i = 1; i <= length; ++i) { - fprintf(stderr, "%02X ", data[i-1] & 0xFF); - if (!(i % 20)) { - fprintf(stderr, "\n## "); - } + { + const char _sym[] = "><><><"; + if (type) { + for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) { + fprintf(stderr, HTTP_IS_CTYPE(print, *data)?"%c":"\\x%02X", (int) *data); + if (*data == '\n' && length) { + fprintf(stderr, "\n%c ", _sym[type-1]); } - fprintf(stderr, "\n"); - } - if (data[length-1] != 0xa) { - fprintf(stderr, "\n"); } -#endif -#if 0 - fprintf(stderr, "%.*s%s", length, data, data[length-1]=='\n'?"":"\n"); -#endif - break; + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "# %s", data); + } } - +#endif + if (type) { request->conv.last_type = type; }