LTP GCOV extension - code coverage report
Current view: directory - ext/http - http_request_api.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 459
Code covered: 76.7 % Executed lines: 352
Legend: not executed executed

       1                 : /*
       2                 :     +--------------------------------------------------------------------+
       3                 :     | PECL :: http                                                       |
       4                 :     +--------------------------------------------------------------------+
       5                 :     | Redistribution and use in source and binary forms, with or without |
       6                 :     | modification, are permitted provided that the conditions mentioned |
       7                 :     | in the accompanying LICENSE file are met.                          |
       8                 :     +--------------------------------------------------------------------+
       9                 :     | Copyright (c) 2004-2007, Michael Wallner <mike@php.net>            |
      10                 :     +--------------------------------------------------------------------+
      11                 : */
      12                 : 
      13                 : /* $Id: http_request_api.c,v 1.155 2007/02/23 08:03:24 mike Exp $ */
      14                 : 
      15                 : #define HTTP_WANT_SAPI
      16                 : #define HTTP_WANT_CURL
      17                 : #include "php_http.h"
      18                 : 
      19                 : #ifdef HTTP_HAVE_CURL
      20                 : 
      21                 : #include "php_http_api.h"
      22                 : #include "php_http_persistent_handle_api.h"
      23                 : #include "php_http_request_api.h"
      24                 : #include "php_http_url_api.h"
      25                 : 
      26                 : #ifdef ZEND_ENGINE_2
      27                 : #       include "php_http_request_object.h"
      28                 : #endif
      29                 : 
      30                 : #include "php_http_request_int.h"
      31                 : 
      32                 : /* {{{ cruft for thread safe SSL crypto locks */
      33                 : #ifdef HTTP_NEED_OPENSSL_TSL
      34                 : static MUTEX_T *http_openssl_tsl = NULL;
      35                 : 
      36                 : static void http_openssl_thread_lock(int mode, int n, const char * file, int line)
      37                 : {
      38                 :         if (mode & CRYPTO_LOCK) {
      39                 :                 tsrm_mutex_lock(http_openssl_tsl[n]);
      40                 :         } else {
      41                 :                 tsrm_mutex_unlock(http_openssl_tsl[n]);
      42                 :         }
      43                 : }
      44                 : 
      45                 : static ulong http_openssl_thread_id(void)
      46                 : {
      47                 :         return (ulong) tsrm_thread_id();
      48                 : }
      49                 : #endif
      50                 : #ifdef HTTP_NEED_GNUTLS_TSL
      51                 : static int http_gnutls_mutex_create(void **m)
      52                 : {
      53                 :         if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
      54                 :                 return SUCCESS;
      55                 :         } else {
      56                 :                 return FAILURE;
      57                 :         }
      58                 : }
      59                 : 
      60                 : static int http_gnutls_mutex_destroy(void **m)
      61                 : {
      62                 :         tsrm_mutex_free(*((MUTEX_T *) m));
      63                 :         return SUCCESS;
      64                 : }
      65                 : 
      66                 : static int http_gnutls_mutex_lock(void **m)
      67                 : {
      68                 :         return tsrm_mutex_lock(*((MUTEX_T *) m));
      69                 : }
      70                 : 
      71                 : static int http_gnutls_mutex_unlock(void **m)
      72                 : {
      73                 :         return tsrm_mutex_unlock(*((MUTEX_T *) m));
      74                 : }
      75                 : 
      76                 : static struct gcry_thread_cbs http_gnutls_tsl = {
      77                 :         GCRY_THREAD_OPTION_USER,
      78                 :         NULL,
      79                 :         http_gnutls_mutex_create,
      80                 :         http_gnutls_mutex_destroy,
      81                 :         http_gnutls_mutex_lock,
      82                 :         http_gnutls_mutex_unlock
      83                 : };
      84                 : #endif
      85                 : /* }}} */
      86                 : 
      87                 : /* {{{ MINIT */
      88                 : PHP_MINIT_FUNCTION(http_request)
      89             220 : {
      90                 : #ifdef HTTP_NEED_OPENSSL_TSL
      91                 :         /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */
      92                 :         if (!CRYPTO_get_id_callback()) {
      93                 :                 int i, c = CRYPTO_num_locks();
      94                 :                 
      95                 :                 http_openssl_tsl = malloc(c * sizeof(MUTEX_T));
      96                 :                 
      97                 :                 for (i = 0; i < c; ++i) {
      98                 :                         http_openssl_tsl[i] = tsrm_mutex_alloc();
      99                 :                 }
     100                 :                 
     101                 :                 CRYPTO_set_id_callback(http_openssl_thread_id);
     102                 :                 CRYPTO_set_locking_callback(http_openssl_thread_lock);
     103                 :         }
     104                 : #endif
     105                 : #ifdef HTTP_NEED_GNUTLS_TSL
     106                 :         gcry_control(GCRYCTL_SET_THREAD_CBS, &http_gnutls_tsl);
     107                 : #endif
     108                 : 
     109             220 :         if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) {
     110               0 :                 return FAILURE;
     111                 :         }
     112                 :         
     113             220 :         if (SUCCESS != http_persistent_handle_provide("http_request", curl_easy_init, curl_easy_cleanup, curl_easy_duphandle)) {
     114               0 :                 return FAILURE;
     115                 :         }
     116                 :         
     117             220 :         HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC);
     118             220 :         HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST);
     119             220 :         HTTP_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM);
     120             220 :         HTTP_LONG_CONSTANT("HTTP_AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE);
     121             220 :         HTTP_LONG_CONSTANT("HTTP_AUTH_ANY", CURLAUTH_ANY);
     122                 :         
     123             220 :         HTTP_LONG_CONSTANT("HTTP_VERSION_NONE", CURL_HTTP_VERSION_NONE); /* to be removed */
     124             220 :         HTTP_LONG_CONSTANT("HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0);
     125             220 :         HTTP_LONG_CONSTANT("HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1);
     126             220 :         HTTP_LONG_CONSTANT("HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE);
     127                 :         
     128             220 :         HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1);
     129             220 :         HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2);
     130             220 :         HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3);
     131             220 :         HTTP_LONG_CONSTANT("HTTP_SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT);
     132                 :         
     133             220 :         HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_V4", CURL_IPRESOLVE_V4);
     134             220 :         HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_V6", CURL_IPRESOLVE_V6);
     135             220 :         HTTP_LONG_CONSTANT("HTTP_IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER);
     136                 : 
     137                 : #if HTTP_CURL_VERSION(7,15,2)
     138             220 :         HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS4", CURLPROXY_SOCKS4);
     139                 : #endif
     140             220 :         HTTP_LONG_CONSTANT("HTTP_PROXY_SOCKS5", CURLPROXY_SOCKS5);
     141             220 :         HTTP_LONG_CONSTANT("HTTP_PROXY_HTTP", CURLPROXY_HTTP);
     142             220 :         return SUCCESS;
     143                 : }
     144                 : /* }}} */
     145                 : 
     146                 : /* {{{ MSHUTDOWN */
     147                 : PHP_MSHUTDOWN_FUNCTION(http_request)
     148             219 : {
     149             219 :         curl_global_cleanup();
     150                 : #ifdef HTTP_NEED_OPENSSL_TSL
     151                 :         if (http_openssl_tsl) {
     152                 :                 int i, c = CRYPTO_num_locks();
     153                 :                         
     154                 :                 CRYPTO_set_id_callback(NULL);
     155                 :                 CRYPTO_set_locking_callback(NULL);
     156                 :                         
     157                 :                 for (i = 0; i < c; ++i) {
     158                 :                         tsrm_mutex_free(http_openssl_tsl[i]);
     159                 :                 }
     160                 :                         
     161                 :                 free(http_openssl_tsl);
     162                 :                 http_openssl_tsl = NULL;
     163                 :         }
     164                 : #endif
     165             219 :         return SUCCESS;
     166                 : }
     167                 : /* }}} */
     168                 : 
     169                 : /* {{{ forward declarations */
     170                 : #define http_request_option(r, o, k, t) _http_request_option_ex((r), (o), (k), sizeof(k), (t) TSRMLS_CC)
     171                 : #define http_request_option_ex(r, o, k, l, t) _http_request_option_ex((r), (o), (k), (l), (t) TSRMLS_CC)
     172                 : static inline zval *_http_request_option_ex(http_request *request, HashTable *options, char *key, size_t keylen, int type TSRMLS_DC);
     173                 : #define http_request_option_cache(r, k, z) _http_request_option_cache_ex((r), (k), sizeof(k), 0, (z) TSRMLS_CC)
     174                 : #define http_request_option_cache_ex(r, k, kl, h, z) _http_request_option_cache_ex((r), (k), (kl), (h), (z) TSRMLS_CC)
     175                 : static inline zval *_http_request_option_cache_ex(http_request *r, char *key, size_t keylen, ulong h, zval *opt TSRMLS_DC);
     176                 : 
     177                 : static size_t http_curl_read_callback(void *, size_t, size_t, void *);
     178                 : static int http_curl_progress_callback(void *, double, double, double, double);
     179                 : static int http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *);
     180            1012 : static int http_curl_dummy_callback(char *data, size_t n, size_t l, void *s) { return n*l; }
     181                 : static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *);
     182                 : /* }}} */
     183                 : 
     184                 : /* {{{ CURL *http_curl_init(http_request *) */
     185                 : PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC)
     186              83 : {
     187              83 :         if (ch || (SUCCESS == http_persistent_handle_acquire("http_request", &ch))) {
     188                 : #if defined(ZTS)
     189                 :                 curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L);
     190                 : #endif
     191              83 :                 curl_easy_setopt(ch, CURLOPT_HEADER, 0L);
     192              83 :                 curl_easy_setopt(ch, CURLOPT_FILETIME, 1L);
     193              83 :                 curl_easy_setopt(ch, CURLOPT_AUTOREFERER, 1L);
     194              83 :                 curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
     195              83 :                 curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, NULL);
     196              83 :                 curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, http_curl_raw_callback);
     197              83 :                 curl_easy_setopt(ch, CURLOPT_READFUNCTION, http_curl_read_callback);
     198              83 :                 curl_easy_setopt(ch, CURLOPT_IOCTLFUNCTION, http_curl_ioctl_callback);
     199              83 :                 curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, http_curl_dummy_callback);
     200                 :                 
     201                 :                 /* set context */
     202              83 :                 if (request) {
     203              83 :                         curl_easy_setopt(ch, CURLOPT_PRIVATE, request);
     204              83 :                         curl_easy_setopt(ch, CURLOPT_DEBUGDATA, request);
     205              83 :                         curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, request->_error);
     206                 :                         
     207                 :                         /* attach curl handle */
     208              83 :                         request->ch = ch;
     209                 :                         /* set defaults (also in http_request_reset()) */
     210              83 :                         http_request_defaults(request);
     211                 :                 }
     212                 :         }
     213                 :         
     214              83 :         return ch;
     215                 : }
     216                 : /* }}} */
     217                 : 
     218                 : /* {{{ CURL *http_curl_copy(CURL *) */
     219                 : PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC)
     220               0 : {
     221                 :         CURL *copy;
     222                 :         
     223               0 :         if (SUCCESS == http_persistent_handle_accrete("http_request", ch, &copy)) {
     224               0 :                 return copy;
     225                 :         }
     226               0 :         return NULL;
     227                 : }
     228                 : /* }}} */
     229                 : 
     230                 : /* {{{ void http_curl_free(CURL **) */
     231                 : PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC)
     232              91 : {
     233              91 :         if (*ch) {
     234              83 :                 curl_easy_setopt(*ch, CURLOPT_NOPROGRESS, 1L);
     235              83 :                 curl_easy_setopt(*ch, CURLOPT_PROGRESSFUNCTION, NULL);
     236              83 :                 curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L);
     237              83 :                 curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL);
     238                 :                 
     239              83 :                 http_persistent_handle_release("http_request", ch);
     240                 :         }
     241              91 : }
     242                 : /* }}} */
     243                 : 
     244                 : /* {{{ http_request *http_request_init(http_request *) */
     245                 : PHP_HTTP_API http_request *_http_request_init_ex(http_request *request, CURL *ch, http_request_method meth, const char *url ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
     246              91 : {
     247                 :         http_request *r;
     248                 :         
     249              91 :         if (request) {
     250               6 :                 r = request;
     251                 :         } else {
     252              85 :                 r = emalloc_rel(sizeof(http_request));
     253                 :         }
     254              91 :         memset(r, 0, sizeof(http_request));
     255                 :         
     256              91 :         r->ch = ch;
     257              91 :         r->url = (url) ? http_absolute_url(url) : NULL;
     258              91 :         r->meth = (meth > 0) ? meth : HTTP_GET;
     259                 :         
     260              91 :         phpstr_init(&r->conv.request);
     261              91 :         phpstr_init_ex(&r->conv.response, HTTP_CURLBUF_SIZE, 0);
     262              91 :         phpstr_init(&r->_cache.cookies);
     263              91 :         zend_hash_init(&r->_cache.options, 0, NULL, ZVAL_PTR_DTOR, 0);
     264                 :         
     265                 :         TSRMLS_SET_CTX(r->tsrm_ls);
     266                 :         
     267              91 :         return r;
     268                 : }
     269                 : /* }}} */
     270                 : 
     271                 : /* {{{ void http_request_dtor(http_request *) */
     272                 : PHP_HTTP_API void _http_request_dtor(http_request *request)
     273              91 : {
     274                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     275                 :         
     276              91 :         http_curl_free(&request->ch);
     277              91 :         http_request_reset(request);
     278                 :         
     279              91 :         phpstr_dtor(&request->_cache.cookies);
     280              91 :         zend_hash_destroy(&request->_cache.options);
     281              91 :         if (request->_cache.headers) {
     282              53 :                 curl_slist_free_all(request->_cache.headers);
     283              53 :                 request->_cache.headers = NULL;
     284                 :         }
     285              91 :         if (request->_progress_callback) {
     286               0 :                 zval_ptr_dtor(&request->_progress_callback);
     287               0 :                 request->_progress_callback = NULL;
     288                 :         }
     289              91 : }
     290                 : /* }}} */
     291                 : 
     292                 : /* {{{ void http_request_free(http_request **) */
     293                 : PHP_HTTP_API void _http_request_free(http_request **request)
     294              85 : {
     295              85 :         if (*request) {
     296                 :                 TSRMLS_FETCH_FROM_CTX((*request)->tsrm_ls);
     297              85 :                 http_request_body_free(&(*request)->body);
     298              85 :                 http_request_dtor(*request);
     299              85 :                 efree(*request);
     300              85 :                 *request = NULL;
     301                 :         }
     302              85 : }
     303                 : /* }}} */
     304                 : 
     305                 : /* {{{ void http_request_reset(http_request *) */
     306                 : PHP_HTTP_API void _http_request_reset(http_request *request)
     307             176 : {
     308                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     309             176 :         STR_SET(request->url, NULL);
     310             176 :         request->conv.last_type = 0;
     311             176 :         phpstr_dtor(&request->conv.request);
     312             176 :         phpstr_dtor(&request->conv.response);
     313             176 :         http_request_body_dtor(request->body);
     314                 :         
     315             176 :         if (request->ch) {
     316              12 :                 http_request_defaults(request);
     317                 :         }
     318             176 :         request->_error[0] = '\0';
     319             176 : }
     320                 : /* }}} */
     321                 : 
     322                 : /* {{{ STATUS http_request_enable_cookies(http_request *) */
     323                 : PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request)
     324               5 : {
     325               5 :         int initialized = 1;
     326                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     327                 :         
     328               5 :         HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0);
     329               5 :         if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, "")) {
     330               5 :                 return SUCCESS;
     331                 :         }
     332               0 :         http_error(HE_WARNING, HTTP_E_REQUEST, "Could not enable cookies for this session");
     333               0 :         return FAILURE;
     334                 : }
     335                 : /* }}} */
     336                 : 
     337                 : /* {{{ STATUS http_request_reset_cookies(http_request *, int) */
     338                 : PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int session_only)
     339               1 : {
     340               1 :         int initialized = 1;
     341                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     342                 :         
     343               1 :         HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0);
     344               1 :         if (session_only) {
     345                 : #if HTTP_CURL_VERSION(7,15,4)
     346               0 :                 if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS")) {
     347               0 :                         return SUCCESS;
     348                 :                 }
     349                 : #endif
     350               0 :                 http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset session cookies (need libcurl >= v7.15.4)");
     351                 :         } else {
     352                 : #if HTTP_CURL_VERSION(7,14,1)
     353               1 :                 if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL")) {
     354               1 :                         return SUCCESS;
     355                 :                 }
     356                 : #endif
     357               0 :                 http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset cookies (need libcurl >= v7.14.1)");
     358                 :         }
     359               0 :         return FAILURE;
     360                 : }
     361                 : /* }}} */
     362                 : 
     363                 : /* {{{ void http_request_defaults(http_request *) */
     364                 : PHP_HTTP_API void _http_request_defaults(http_request *request)
     365              95 : {
     366              95 :         if (request->ch) {
     367              95 :                 HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, NULL);
     368              95 :                 HTTP_CURL_OPT(CURLOPT_URL, NULL);
     369              95 :                 HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 1L);
     370              95 :                 HTTP_CURL_OPT(CURLOPT_PROXY, NULL);
     371              95 :                 HTTP_CURL_OPT(CURLOPT_PROXYPORT, 0L);
     372              95 :                 HTTP_CURL_OPT(CURLOPT_PROXYTYPE, 0L);
     373              95 :                 HTTP_CURL_OPT(CURLOPT_PROXYUSERPWD, NULL);
     374              95 :                 HTTP_CURL_OPT(CURLOPT_PROXYAUTH, 0L);
     375              95 :                 HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, 60L);
     376              95 :                 HTTP_CURL_OPT(CURLOPT_IPRESOLVE, 0);
     377              95 :                 HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, 0L);
     378              95 :                 HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, 0L);
     379                 : #if HTTP_CURL_VERSION(7,15,5)
     380                 :                 HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) 0);
     381                 :                 HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) 0);
     382                 : #endif
     383                 :                 /* crashes
     384                 :                 HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, 5L); */
     385              95 :                 HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 0L);
     386              95 :                 HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 0L);
     387              95 :                 HTTP_CURL_OPT(CURLOPT_INTERFACE, NULL);
     388              95 :                 HTTP_CURL_OPT(CURLOPT_PORT, 0L);
     389                 : #if HTTP_CURL_VERSION(7,15,2)
     390              95 :                 HTTP_CURL_OPT(CURLOPT_LOCALPORT, 0L);
     391              95 :                 HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, 0L);
     392                 : #endif
     393              95 :                 HTTP_CURL_OPT(CURLOPT_USERPWD, NULL);
     394              95 :                 HTTP_CURL_OPT(CURLOPT_HTTPAUTH, 0L);
     395              95 :                 HTTP_CURL_OPT(CURLOPT_ENCODING, NULL);
     396              95 :                 HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, 0L);
     397              95 :                 HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, 0L);
     398              95 :                 HTTP_CURL_OPT(CURLOPT_REFERER, NULL);
     399              95 :                 HTTP_CURL_OPT(CURLOPT_USERAGENT, "PECL::HTTP/" PHP_EXT_HTTP_VERSION " (PHP/" PHP_VERSION ")");
     400              95 :                 HTTP_CURL_OPT(CURLOPT_HTTPHEADER, NULL);
     401              95 :                 HTTP_CURL_OPT(CURLOPT_COOKIE, NULL);
     402                 : #if HTTP_CURL_VERSION(7,14,1)
     403              95 :                 HTTP_CURL_OPT(CURLOPT_COOKIELIST, NULL);
     404                 : #endif
     405              95 :                 HTTP_CURL_OPT(CURLOPT_RANGE, NULL);
     406              95 :                 HTTP_CURL_OPT(CURLOPT_RESUME_FROM, 0L);
     407              95 :                 HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, 0L);
     408              95 :                 HTTP_CURL_OPT(CURLOPT_TIMECONDITION, 0L);
     409              95 :                 HTTP_CURL_OPT(CURLOPT_TIMEVALUE, 0L);
     410              95 :                 HTTP_CURL_OPT(CURLOPT_TIMEOUT, 0L);
     411              95 :                 HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, 3);
     412              95 :                 HTTP_CURL_OPT(CURLOPT_SSLCERT, NULL);
     413              95 :                 HTTP_CURL_OPT(CURLOPT_SSLCERTTYPE, NULL);
     414              95 :                 HTTP_CURL_OPT(CURLOPT_SSLCERTPASSWD, NULL);
     415              95 :                 HTTP_CURL_OPT(CURLOPT_SSLKEY, NULL);
     416              95 :                 HTTP_CURL_OPT(CURLOPT_SSLKEYTYPE, NULL);
     417              95 :                 HTTP_CURL_OPT(CURLOPT_SSLKEYPASSWD, NULL);
     418              95 :                 HTTP_CURL_OPT(CURLOPT_SSLENGINE, NULL);
     419              95 :                 HTTP_CURL_OPT(CURLOPT_SSLVERSION, 0L);
     420              95 :                 HTTP_CURL_OPT(CURLOPT_SSL_VERIFYPEER, 0L);
     421              95 :                 HTTP_CURL_OPT(CURLOPT_SSL_VERIFYHOST, 0L);
     422              95 :                 HTTP_CURL_OPT(CURLOPT_SSL_CIPHER_LIST, NULL);
     423                 : #ifdef HTTP_CURL_CAINFO
     424              95 :                 HTTP_CURL_OPT(CURLOPT_CAINFO, HTTP_CURL_CAINFO);
     425                 : #else
     426                 :                 HTTP_CURL_OPT(CURLOPT_CAINFO, NULL);
     427                 : #endif
     428              95 :                 HTTP_CURL_OPT(CURLOPT_CAPATH, NULL);
     429              95 :                 HTTP_CURL_OPT(CURLOPT_RANDOM_FILE, NULL);
     430              95 :                 HTTP_CURL_OPT(CURLOPT_EGDSOCKET, NULL);
     431              95 :                 HTTP_CURL_OPT(CURLOPT_POSTFIELDS, NULL);
     432              95 :                 HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, 0L);
     433              95 :                 HTTP_CURL_OPT(CURLOPT_HTTPPOST, NULL);
     434              95 :                 HTTP_CURL_OPT(CURLOPT_IOCTLDATA, NULL);
     435              95 :                 HTTP_CURL_OPT(CURLOPT_READDATA, NULL);
     436              95 :                 HTTP_CURL_OPT(CURLOPT_INFILESIZE, 0L);
     437              95 :                 HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
     438              95 :                 HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, NULL);
     439              95 :                 HTTP_CURL_OPT(CURLOPT_NOBODY, 0L);
     440              95 :                 HTTP_CURL_OPT(CURLOPT_POST, 0L);
     441              95 :                 HTTP_CURL_OPT(CURLOPT_UPLOAD, 0L);
     442              95 :                 HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L);
     443                 :         }
     444              95 : }
     445                 : /* }}} */
     446                 : 
     447                 : PHP_HTTP_API void _http_request_set_progress_callback(http_request *request, zval *cb)
     448              86 : {
     449              86 :         if (request->_progress_callback) {
     450               3 :                 zval_ptr_dtor(&request->_progress_callback);
     451                 :         }
     452              86 :         if ((request->_progress_callback = cb)) {
     453               3 :                 ZVAL_ADDREF(cb);
     454               3 :                 HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 0);
     455               3 :                 HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, request);
     456               3 :                 HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, http_curl_progress_callback);
     457                 :         } else {
     458              83 :                 HTTP_CURL_OPT(CURLOPT_NOPROGRESS, 1);
     459              83 :                 HTTP_CURL_OPT(CURLOPT_PROGRESSDATA, NULL);
     460              83 :                 HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION, NULL);
     461                 :         }
     462              86 : }
     463                 : 
     464                 : /* {{{ STATUS http_request_prepare(http_request *, HashTable *) */
     465                 : PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *options)
     466              91 : {
     467                 :         zval *zoption;
     468              91 :         zend_bool range_req = 0;
     469                 : 
     470                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     471                 :         
     472              91 :         HTTP_CHECK_CURL_INIT(request->ch, http_curl_init(request), return FAILURE);
     473                 :         
     474                 :         /* set options */
     475              91 :         HTTP_CURL_OPT(CURLOPT_URL, request->url);
     476                 : 
     477                 :         /* progress callback */
     478              91 :         if ((zoption = http_request_option(request, options, "onprogress", -1))) {
     479               0 :                 http_request_set_progress_callback(request, zoption);
     480                 :         }
     481                 : 
     482                 :         /* proxy */
     483              91 :         if ((zoption = http_request_option(request, options, "proxyhost", IS_STRING))) {
     484               0 :                 HTTP_CURL_OPT(CURLOPT_PROXY, Z_STRVAL_P(zoption));
     485                 :                 /* type */
     486               0 :                 if ((zoption = http_request_option(request, options, "proxytype", IS_LONG))) {
     487               0 :                         HTTP_CURL_OPT(CURLOPT_PROXYTYPE, Z_LVAL_P(zoption));
     488                 :                 }
     489                 :                 /* port */
     490               0 :                 if ((zoption = http_request_option(request, options, "proxyport", IS_LONG))) {
     491               0 :                         HTTP_CURL_OPT(CURLOPT_PROXYPORT, Z_LVAL_P(zoption));
     492                 :                 }
     493                 :                 /* user:pass */
     494               0 :                 if ((zoption = http_request_option(request, options, "proxyauth", IS_STRING)) && Z_STRLEN_P(zoption)) {
     495               0 :                         HTTP_CURL_OPT(CURLOPT_PROXYUSERPWD, Z_STRVAL_P(zoption));
     496                 :                 }
     497                 :                 /* auth method */
     498               0 :                 if ((zoption = http_request_option(request, options, "proxyauthtype", IS_LONG))) {
     499               0 :                         HTTP_CURL_OPT(CURLOPT_PROXYAUTH, Z_LVAL_P(zoption));
     500                 :                 }
     501                 :         }
     502                 : 
     503                 :         /* dns */
     504              91 :         if ((zoption = http_request_option(request, options, "dns_cache_timeout", IS_LONG))) {
     505               0 :                 HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT, Z_LVAL_P(zoption));
     506                 :         }
     507              91 :         if ((zoption = http_request_option(request, options, "ipresolve", IS_LONG)) && Z_LVAL_P(zoption)) {
     508               0 :                 HTTP_CURL_OPT(CURLOPT_IPRESOLVE, Z_LVAL_P(zoption));
     509                 :         }
     510                 :         
     511                 :         /* limits */
     512              91 :         if ((zoption = http_request_option(request, options, "low_speed_limit", IS_LONG))) {
     513               0 :                 HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT, Z_LVAL_P(zoption));
     514                 :         }
     515              91 :         if ((zoption = http_request_option(request, options, "low_speed_time", IS_LONG))) {
     516               0 :                 HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME, Z_LVAL_P(zoption));
     517                 :         }
     518                 : #if HTTP_CURL_VERSION(7,15,5)
     519                 :         if ((zoption = http_request_option(request, options, "max_send_speed", IS_LONG))) {
     520                 :                 HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
     521                 :         }
     522                 :         if ((zoption = http_request_option(request, options, "max_recv_speed", IS_LONG))) {
     523                 :                 HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
     524                 :         }
     525                 : #endif
     526                 :         /* crashes
     527                 :         if ((zoption = http_request_option(request, options, "maxconnects", IS_LONG))) {
     528                 :                 HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, Z_LVAL_P(zoption));
     529                 :         } */
     530              91 :         if ((zoption = http_request_option(request, options, "fresh_connect", IS_BOOL)) && Z_BVAL_P(zoption)) {
     531               0 :                 HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT, 1L);
     532                 :         }
     533              91 :         if ((zoption = http_request_option(request, options, "forbid_reuse", IS_BOOL)) && Z_BVAL_P(zoption)) {
     534               0 :                 HTTP_CURL_OPT(CURLOPT_FORBID_REUSE, 1L);
     535                 :         }
     536                 :         
     537                 :         /* outgoing interface */
     538              91 :         if ((zoption = http_request_option(request, options, "interface", IS_STRING))) {
     539               0 :                 HTTP_CURL_OPT(CURLOPT_INTERFACE, Z_STRVAL_P(zoption));
     540                 :                 
     541                 : #if HTTP_CURL_VERSION(7,15,2)
     542               0 :                 if ((zoption = http_request_option(request, options, "portrange", IS_ARRAY))) {
     543                 :                         zval **prs, **pre;
     544                 :                         
     545               0 :                         zend_hash_internal_pointer_reset(Z_ARRVAL_P(zoption));
     546               0 :                         if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &prs)) {
     547               0 :                                 zend_hash_move_forward(Z_ARRVAL_P(zoption));
     548               0 :                                 if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void *) &pre)) {
     549               0 :                                         zval *prs_cpy = zval_copy(IS_LONG, *prs), *pre_cpy = zval_copy(IS_LONG, *pre);
     550                 :                                         
     551               0 :                                         if (Z_LVAL_P(prs_cpy) && Z_LVAL_P(pre_cpy)) {
     552               0 :                                                 HTTP_CURL_OPT(CURLOPT_LOCALPORT, MIN(Z_LVAL_P(prs_cpy), Z_LVAL_P(pre_cpy)));
     553               0 :                                                 HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE, labs(Z_LVAL_P(prs_cpy)-Z_LVAL_P(pre_cpy))+1L);
     554                 :                                         }
     555               0 :                                         zval_free(&prs_cpy);
     556               0 :                                         zval_free(&pre_cpy);
     557                 :                                 }
     558                 :                         }
     559                 :                 }
     560                 : #endif
     561                 :         }
     562                 : 
     563                 :         /* another port */
     564              91 :         if ((zoption = http_request_option(request, options, "port", IS_LONG))) {
     565               0 :                 HTTP_CURL_OPT(CURLOPT_PORT, Z_LVAL_P(zoption));
     566                 :         }
     567                 : 
     568                 :         /* auth */
     569              91 :         if ((zoption = http_request_option(request, options, "httpauth", IS_STRING)) && Z_STRLEN_P(zoption)) {
     570               0 :                 HTTP_CURL_OPT(CURLOPT_USERPWD, Z_STRVAL_P(zoption));
     571                 :         }
     572              91 :         if ((zoption = http_request_option(request, options, "httpauthtype", IS_LONG))) {
     573               0 :                 HTTP_CURL_OPT(CURLOPT_HTTPAUTH, Z_LVAL_P(zoption));
     574                 :         }
     575                 : 
     576                 :         /* redirects, defaults to 0 */
     577              91 :         if ((zoption = http_request_option(request, options, "redirect", IS_LONG))) {
     578              52 :                 HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION, Z_LVAL_P(zoption) ? 1L : 0L);
     579              52 :                 HTTP_CURL_OPT(CURLOPT_MAXREDIRS, Z_LVAL_P(zoption));
     580              52 :                 if ((zoption = http_request_option(request, options, "unrestrictedauth", IS_BOOL))) {
     581               0 :                         HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH, Z_LVAL_P(zoption));
     582                 :                 }
     583                 :         }
     584                 : 
     585                 :         /* referer */
     586              91 :         if ((zoption = http_request_option(request, options, "referer", IS_STRING)) && Z_STRLEN_P(zoption)) {
     587               0 :                 HTTP_CURL_OPT(CURLOPT_REFERER, Z_STRVAL_P(zoption));
     588                 :         }
     589                 : 
     590                 :         /* useragent, default "PECL::HTTP/version (PHP/version)" */
     591              91 :         if ((zoption = http_request_option(request, options, "useragent", IS_STRING))) {
     592                 :                 /* allow to send no user agent, not even default one */
     593               0 :                 if (Z_STRLEN_P(zoption)) {
     594               0 :                         HTTP_CURL_OPT(CURLOPT_USERAGENT, Z_STRVAL_P(zoption));
     595                 :                 } else {
     596               0 :                         HTTP_CURL_OPT(CURLOPT_USERAGENT, NULL);
     597                 :                 }
     598                 :         }
     599                 : 
     600                 :         /* resume */
     601              91 :         if ((zoption = http_request_option(request, options, "resume", IS_LONG)) && (Z_LVAL_P(zoption) > 0)) {
     602               0 :                 range_req = 1;
     603               0 :                 HTTP_CURL_OPT(CURLOPT_RESUME_FROM, Z_LVAL_P(zoption));
     604                 :         }
     605                 :         /* or range of kind array(array(0,499), array(100,1499)) */
     606              91 :         else if ((zoption = http_request_option(request, options, "range", IS_ARRAY)) && zend_hash_num_elements(Z_ARRVAL_P(zoption))) {
     607                 :                 HashPosition pos1, pos2;
     608                 :                 zval **rr, **rb, **re;
     609                 :                 phpstr rs;
     610                 :                 
     611               0 :                 phpstr_init(&rs);
     612               0 :                 FOREACH_VAL(pos1, zoption, rr) {
     613               0 :                         if (Z_TYPE_PP(rr) == IS_ARRAY) {
     614               0 :                                 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(rr), &pos2);
     615               0 :                                 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &rb, &pos2)) {
     616               0 :                                         zend_hash_move_forward_ex(Z_ARRVAL_PP(rr), &pos2);
     617               0 :                                         if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr), (void *) &re, &pos2)) {
     618               0 :                                                 if (    ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) &&
     619                 :                                                                 ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) {
     620               0 :                                                         zval *rbl = zval_copy(IS_LONG, *rb), *rel = zval_copy(IS_LONG, *re);
     621                 :                                                         
     622               0 :                                                         if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) {
     623               0 :                                                                 phpstr_appendf(&rs, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel));
     624                 :                                                         }
     625               0 :                                                         zval_free(&rbl);
     626               0 :                                                         zval_free(&rel);
     627                 :                                                 }
     628                 :                                         }
     629                 :                                 }
     630                 :                         }
     631                 :                 }
     632                 :                 
     633               0 :                 if (PHPSTR_LEN(&rs)) {
     634                 :                         zval *cached_range;
     635                 :                         
     636                 :                         /* ditch last comma */
     637               0 :                         PHPSTR_VAL(&rs)[PHPSTR_LEN(&rs)-- -1] = '\0';
     638                 :                         /* cache string */
     639               0 :                         MAKE_STD_ZVAL(cached_range);
     640               0 :                         ZVAL_STRINGL(cached_range, PHPSTR_VAL(&rs), PHPSTR_LEN(&rs), 0);
     641               0 :                         HTTP_CURL_OPT(CURLOPT_RANGE, Z_STRVAL_P(http_request_option_cache(request, "range", cached_range)));
     642               0 :                         zval_ptr_dtor(&cached_range);
     643                 :                 }
     644                 :         }
     645                 : 
     646                 :         /* additional headers, array('name' => 'value') */
     647              91 :         if (request->_cache.headers) {
     648               0 :                 curl_slist_free_all(request->_cache.headers);
     649               0 :                 request->_cache.headers = NULL;
     650                 :         }
     651              91 :         if ((zoption = http_request_option(request, options, "headers", IS_ARRAY))) {
     652               2 :                 HashKey header_key = initHashKey(0);
     653                 :                 zval **header_val;
     654                 :                 HashPosition pos;
     655                 : 
     656               4 :                 FOREACH_KEYVAL(pos, zoption, header_key, header_val) {
     657               2 :                         if (header_key.type == HASH_KEY_IS_STRING) {
     658                 :                                 char header[1024];
     659                 :                                 
     660               2 :                                 ZVAL_ADDREF(*header_val);
     661               2 :                                 convert_to_string_ex(header_val);
     662               2 :                                 if (!strcasecmp(header_key.str, "range")) {
     663               0 :                                         range_req = 1;
     664                 :                                 }
     665               2 :                                 snprintf(header, sizeof(header), "%s: %s", header_key.str, Z_STRVAL_PP(header_val));
     666               2 :                                 request->_cache.headers = curl_slist_append(request->_cache.headers, header);
     667               2 :                                 zval_ptr_dtor(header_val);
     668                 :                         }
     669                 :                 }
     670                 :         }
     671                 :         /* etag */
     672              91 :         if ((zoption = http_request_option(request, options, "etag", IS_STRING)) && Z_STRLEN_P(zoption)) {
     673               1 :                 char match_header[1024], *quoted_etag = NULL;
     674                 :                 
     675               1 :                 if ((Z_STRVAL_P(zoption)[0] != '"') || (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] != '"')) {
     676               0 :                         spprintf(&quoted_etag, 0, "\"%s\"", Z_STRVAL_P(zoption));
     677                 :                 }
     678               1 :                 snprintf(match_header, sizeof(match_header), "%s: %s", range_req?"If-Match":"If-None-Match", quoted_etag?quoted_etag:Z_STRVAL_P(zoption));
     679               1 :                 request->_cache.headers = curl_slist_append(request->_cache.headers, match_header);
     680               1 :                 STR_FREE(quoted_etag);
     681                 :         }
     682                 :         /* compression */
     683              91 :         if ((zoption = http_request_option(request, options, "compress", IS_BOOL)) && Z_LVAL_P(zoption)) {
     684              50 :                 request->_cache.headers = curl_slist_append(request->_cache.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5");
     685                 :         }
     686              91 :         HTTP_CURL_OPT(CURLOPT_HTTPHEADER, request->_cache.headers);
     687                 : 
     688                 :         /* lastmodified */
     689              91 :         if ((zoption = http_request_option(request, options, "lastmodified", IS_LONG))) {
     690              49 :                 if (Z_LVAL_P(zoption)) {
     691              49 :                         if (Z_LVAL_P(zoption) > 0) {
     692              49 :                                 HTTP_CURL_OPT(CURLOPT_TIMEVALUE, Z_LVAL_P(zoption));
     693                 :                         } else {
     694               0 :                                 HTTP_CURL_OPT(CURLOPT_TIMEVALUE, (long) HTTP_G->request.time + Z_LVAL_P(zoption));
     695                 :                         }
     696              49 :                         HTTP_CURL_OPT(CURLOPT_TIMECONDITION, (long) (range_req ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE));
     697                 :                 } else {
     698               0 :                         HTTP_CURL_OPT(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
     699                 :                 }
     700                 :         }
     701                 : 
     702                 :         /* cookies, array('name' => 'value') */
     703              91 :         if ((zoption = http_request_option(request, options, "cookies", IS_ARRAY))) {
     704               3 :                 phpstr_dtor(&request->_cache.cookies);
     705               3 :                 if (zend_hash_num_elements(Z_ARRVAL_P(zoption))) {
     706               3 :                         zval *urlenc_cookies = NULL;
     707                 :                         /* check whether cookies should not be urlencoded; default is to urlencode them */
     708               5 :                         if ((!(urlenc_cookies = http_request_option(request, options, "encodecookies", IS_BOOL))) || Z_BVAL_P(urlenc_cookies)) {
     709               2 :                                 if (SUCCESS == http_urlencode_hash_recursive(HASH_OF(zoption), &request->_cache.cookies, "; ", lenof("; "), NULL, 0)) {
     710               2 :                                         phpstr_fix(&request->_cache.cookies);
     711               2 :                                         HTTP_CURL_OPT(CURLOPT_COOKIE, request->_cache.cookies.data);
     712                 :                                 }
     713                 :                         } else {
     714                 :                                 HashPosition pos;
     715               1 :                                 HashKey cookie_key = initHashKey(0);
     716                 :                                 zval **cookie_val;
     717                 :                                 
     718               2 :                                 FOREACH_KEYVAL(pos, zoption, cookie_key, cookie_val) {
     719               1 :                                         if (cookie_key.type == HASH_KEY_IS_STRING) {
     720               1 :                                                 zval *val = zval_copy(IS_STRING, *cookie_val);
     721               1 :                                                 phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(val));
     722               1 :                                                 zval_free(&val);
     723                 :                                         }
     724                 :                                 }
     725                 :                                 
     726               1 :                                 phpstr_fix(&request->_cache.cookies);
     727               1 :                                 if (PHPSTR_LEN(&request->_cache.cookies)) {
     728               1 :                                         HTTP_CURL_OPT(CURLOPT_COOKIE, PHPSTR_VAL(&request->_cache.cookies));
     729                 :                                 }
     730                 :                         }
     731                 :                 }
     732                 :         }
     733                 : 
     734                 :         /* don't load session cookies from cookiestore */
     735              91 :         if ((zoption = http_request_option(request, options, "cookiesession", IS_BOOL)) && Z_BVAL_P(zoption)) {
     736               0 :                 HTTP_CURL_OPT(CURLOPT_COOKIESESSION, 1L);
     737                 :         }
     738                 : 
     739                 :         /* cookiestore, read initial cookies from that file and store cookies back into that file */
     740              91 :         if ((zoption = http_request_option(request, options, "cookiestore", IS_STRING))) {
     741               0 :                 if (Z_STRLEN_P(zoption)) {
     742               0 :                         HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(zoption), return FAILURE);
     743                 :                 }
     744               0 :                 HTTP_CURL_OPT(CURLOPT_COOKIEFILE, Z_STRVAL_P(zoption));
     745               0 :                 HTTP_CURL_OPT(CURLOPT_COOKIEJAR, Z_STRVAL_P(zoption));
     746                 :         }
     747                 : 
     748                 :         /* maxfilesize */
     749              91 :         if ((zoption = http_request_option(request, options, "maxfilesize", IS_LONG))) {
     750               0 :                 HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, Z_LVAL_P(zoption));
     751                 :         }
     752                 : 
     753                 :         /* http protocol */
     754              91 :         if ((zoption = http_request_option(request, options, "protocol", IS_LONG))) {
     755               0 :                 HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, Z_LVAL_P(zoption));
     756                 :         }
     757                 : 
     758                 : #if HTTP_CURL_VERSION(7,16,2)
     759                 :         /* timeout, defaults to 0 */
     760                 :         if ((zoption = http_request_option(request, options, "timeout", IS_DOUBLE))) {
     761                 :                 HTTP_CURL_OPT(CURLOPT_TIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000));
     762                 :         }
     763                 :         /* connecttimeout, defaults to 0 */
     764                 :         if ((zoption = http_request_option(request, options, "connecttimeout", IS_DOUBLE))) {
     765                 :                 HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT_MS, (long)(Z_DVAL_P(zoption)*1000));
     766                 :         }
     767                 : #else
     768                 :         /* timeout, defaults to 0 */
     769              91 :         if ((zoption = http_request_option(request, options, "timeout", IS_LONG))) {
     770              49 :                 HTTP_CURL_OPT(CURLOPT_TIMEOUT, Z_LVAL_P(zoption));
     771                 :         }
     772                 :         /* connecttimeout, defaults to 0 */
     773              91 :         if ((zoption = http_request_option(request, options, "connecttimeout", IS_LONG))) {
     774              49 :                 HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT, Z_LVAL_P(zoption));
     775                 :         }
     776                 : #endif
     777                 : 
     778                 :         /* ssl */
     779              91 :         if ((zoption = http_request_option(request, options, "ssl", IS_ARRAY))) {
     780               2 :                 HashKey key = initHashKey(0);
     781                 :                 zval **param;
     782                 :                 HashPosition pos;
     783                 : 
     784               6 :                 FOREACH_KEYVAL(pos, zoption, key, param) {
     785               4 :                         if (key.type == HASH_KEY_IS_STRING) {
     786               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT, 0, 1);
     787               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE, 0, 0);
     788               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD, 0, 0);
     789                 : 
     790               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLKEY, 0, 0);
     791               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYTYPE, 0, 0);
     792               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYPASSWD, 0, 0);
     793                 : 
     794               4 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSLENGINE, 0, 0);
     795               4 :                                 HTTP_CURL_OPT_LONG(CURLOPT_SSLVERSION, 0);
     796                 : 
     797               2 :                                 HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYPEER, 1);
     798               2 :                                 HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYHOST, 1);
     799               0 :                                 HTTP_CURL_OPT_STRING(CURLOPT_SSL_CIPHER_LIST, 1, 0);
     800                 : 
     801               0 :                                 HTTP_CURL_OPT_STRING(CURLOPT_CAINFO, -3, 1);
     802               0 :                                 HTTP_CURL_OPT_STRING(CURLOPT_CAPATH, -3, 1);
     803               0 :                                 HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE, -3, 1);
     804               0 :                                 HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET, -3, 1);
     805                 :                         }
     806                 :                 }
     807                 :         }
     808                 : 
     809                 :         /* request method */
     810              91 :         switch (request->meth) {
     811                 :                 case HTTP_GET:
     812              75 :                         HTTP_CURL_OPT(CURLOPT_HTTPGET, 1L);
     813              75 :                         break;
     814                 : 
     815                 :                 case HTTP_HEAD:
     816               6 :                         HTTP_CURL_OPT(CURLOPT_NOBODY, 1L);
     817               6 :                         break;
     818                 : 
     819                 :                 case HTTP_POST:
     820               7 :                         HTTP_CURL_OPT(CURLOPT_POST, 1L);
     821               7 :                         break;
     822                 : 
     823                 :                 case HTTP_PUT:
     824               2 :                         HTTP_CURL_OPT(CURLOPT_UPLOAD, 1L);
     825               2 :                         break;
     826                 : 
     827                 :                 default:
     828               1 :                         if (http_request_method_exists(0, request->meth, NULL)) {
     829               1 :                                 HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST, http_request_method_name(request->meth));
     830                 :                         } else {
     831               0 :                                 http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Unsupported request method: %d (%s)", request->meth, request->url);
     832               0 :                                 return FAILURE;
     833                 :                         }
     834                 :                         break;
     835                 :         }
     836                 : 
     837                 :         /* attach request body */
     838              91 :         if (request->body && (request->meth != HTTP_GET) && (request->meth != HTTP_HEAD) && (request->meth != HTTP_OPTIONS)) {
     839              10 :                 switch (request->body->type) {
     840                 :                         case HTTP_REQUEST_BODY_EMPTY:
     841                 :                                 /* nothing */
     842               1 :                                 break;
     843                 :                         
     844                 :                         case HTTP_REQUEST_BODY_CURLPOST:
     845               2 :                                 HTTP_CURL_OPT(CURLOPT_HTTPPOST, (struct curl_httppost *) request->body->data);
     846               2 :                                 break;
     847                 : 
     848                 :                         case HTTP_REQUEST_BODY_CSTRING:
     849               6 :                                 if (request->meth != HTTP_PUT) {
     850               5 :                                         HTTP_CURL_OPT(CURLOPT_POSTFIELDS, request->body->data);
     851               5 :                                         HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE, request->body->size);
     852               5 :                                         break;
     853                 :                                 }
     854                 :                                 /* fallthrough, PUT/UPLOAD _needs_ READDATA */
     855                 :                         case HTTP_REQUEST_BODY_UPLOADFILE:
     856               2 :                                 HTTP_CURL_OPT(CURLOPT_IOCTLDATA, request);
     857               2 :                                 HTTP_CURL_OPT(CURLOPT_READDATA, request);
     858               2 :                                 HTTP_CURL_OPT(CURLOPT_INFILESIZE, request->body->size);
     859               2 :                                 break;
     860                 : 
     861                 :                         default:
     862                 :                                 /* shouldn't ever happen */
     863               0 :                                 http_error_ex(HE_ERROR, 0, "Unknown request body type: %d (%s)", request->body->type, request->url);
     864               0 :                                 return FAILURE;
     865                 :                 }
     866                 :         }
     867                 : 
     868              91 :         return SUCCESS;
     869                 : }
     870                 : /* }}} */
     871                 : 
     872                 : /* {{{ void http_request_exec(http_request *) */
     873                 : PHP_HTTP_API void _http_request_exec(http_request *request)
     874              28 : {
     875                 :         CURLcode result;
     876                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     877                 :         
     878              28 :         if (CURLE_OK != (result = curl_easy_perform(request->ch))) {
     879               0 :                 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(result), request->_error, request->url);
     880                 :         }
     881              28 : }
     882                 : /* }}} */
     883                 : 
     884                 : /* {{{ static size_t http_curl_read_callback(void *, size_t, size_t, void *) */
     885                 : static size_t http_curl_read_callback(void *data, size_t len, size_t n, void *ctx)
     886               5 : {
     887               5 :         http_request *request = (http_request *) ctx;
     888                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     889                 :         
     890               5 :         if (request->body) {
     891               5 :                 switch (request->body->type) {
     892                 :                         case HTTP_REQUEST_BODY_CSTRING:
     893                 :                         {
     894               3 :                                 size_t out = MIN(len * n, request->body->size - request->body->priv);
     895                 :                                 
     896               3 :                                 if (out) {
     897               2 :                                         memcpy(data, ((char *) request->body->data) + request->body->priv, out);
     898               2 :                                         request->body->priv += out;
     899               2 :                                         return out;
     900                 :                                 }
     901               1 :                                 break;
     902                 :                         }
     903                 :                         
     904                 :                         case HTTP_REQUEST_BODY_UPLOADFILE:
     905               2 :                                 return php_stream_read((php_stream *) request->body->data, data, len * n);
     906                 :                 }
     907                 :         }
     908               1 :         return 0;
     909                 : }
     910                 : /* }}} */
     911                 : 
     912                 : /* {{{ static int http_curl_progress_callback(void *, double, double, double, double) */
     913                 : static int http_curl_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
     914               9 : {
     915                 :         zval *param, retval;
     916               9 :         http_request *request = (http_request *) ctx;
     917                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     918                 : 
     919               9 :         INIT_PZVAL(&retval);
     920               9 :         ZVAL_NULL(&retval);
     921                 : 
     922               9 :         MAKE_STD_ZVAL(param);
     923               9 :         array_init(param);
     924               9 :         add_assoc_double(param, "dltotal", dltotal);
     925               9 :         add_assoc_double(param, "dlnow", dlnow);
     926               9 :         add_assoc_double(param, "ultotal", ultotal);
     927               9 :         add_assoc_double(param, "ulnow", ulnow);
     928                 :         
     929               9 :         with_error_handling(EH_NORMAL, NULL) {
     930               9 :                 request->_in_progress_cb = 1;
     931               9 :                 call_user_function(EG(function_table), NULL, request->_progress_callback, &retval, 1, &param TSRMLS_CC);
     932               9 :                 request->_in_progress_cb = 0;
     933               9 :         } end_error_handling();
     934                 :         
     935               9 :         zval_ptr_dtor(&param);
     936               9 :         zval_dtor(&retval);
     937                 :         
     938               9 :         return 0;
     939                 : }
     940                 : /* }}} */
     941                 : 
     942                 : /* {{{ static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *) */
     943                 : static curlioerr http_curl_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx)
     944               0 : {
     945               0 :         http_request *request = (http_request *) ctx;
     946                 :         TSRMLS_FETCH_FROM_CTX(request->tsrm_ls);
     947                 :         
     948               0 :         if (cmd != CURLIOCMD_RESTARTREAD) {
     949               0 :                 return CURLIOE_UNKNOWNCMD;
     950                 :         }
     951                 :         
     952               0 :         if (request->body) {
     953               0 :                 switch (request->body->type) {
     954                 :                         case HTTP_REQUEST_BODY_CSTRING:
     955               0 :                                 request->body->priv = 0;
     956               0 :                                 return CURLIOE_OK;
     957                 :                                 break;
     958                 :                                 
     959                 :                         case HTTP_REQUEST_BODY_UPLOADFILE:
     960               0 :                                 if (SUCCESS == php_stream_rewind((php_stream *) request->body->data)) {
     961               0 :                                         return CURLIOE_OK;
     962                 :                                 }
     963                 :                                 break;
     964                 :                 }
     965                 :         }
     966                 :         
     967               0 :         return CURLIOE_FAILRESTART;
     968                 : }
     969                 : /* }}} */
     970                 : 
     971                 : /* {{{ static int http_curl_raw_callback(CURL *, curl_infotype, char *, size_t, void *) */
     972                 : static int http_curl_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
     973            1930 : {
     974            1930 :         http_request *request = (http_request *) ctx;
     975                 : 
     976                 : #define EMPTY_HEADER(d, l) (!l || (l == 1 && d[0] == '\n') || (l == 2 && d[0] == '\r' && d[1] == '\n'))
     977            1930 :         switch (type) {
     978                 :                 case CURLINFO_DATA_IN:
     979             411 :                         if (request->conv.last_type == CURLINFO_HEADER_IN) {
     980              75 :                                 phpstr_appends(&request->conv.response, HTTP_CRLF);
     981                 :                         }
     982             411 :                         phpstr_append(&request->conv.response, data, length);
     983             411 :                         break;
     984                 :                 case CURLINFO_HEADER_IN:
     985             818 :                         if (!EMPTY_HEADER(data, length)) {
     986             818 :                                 phpstr_append(&request->conv.response, data, length);
     987                 :                         }
     988             818 :                         break;
     989                 :                 case CURLINFO_DATA_OUT:
     990                 :                 case CURLINFO_HEADER_OUT:
     991             108 :                         phpstr_append(&request->conv.request, data, length);
     992                 :                         break;
     993                 :                 default:
     994                 :                         break;
     995                 :         }
     996                 : 
     997                 : #if 0
     998                 :         {
     999                 :                 const char _sym[] = "><><><";
    1000                 :                 if (type) {
    1001                 :                         for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) {
    1002                 :                                 fprintf(stderr, HTTP_IS_CTYPE(print, *data)?"%c":"\\x%02X", (int) *data);
    1003                 :                                 if (*data == '\n' && length) {
    1004                 :                                         fprintf(stderr, "\n%c ", _sym[type-1]);
    1005                 :                                 }
    1006                 :                         }
    1007                 :                         fprintf(stderr, "\n");
    1008                 :                 } else {
    1009                 :                         fprintf(stderr, "# %s", data);
    1010                 :                 }
    1011                 :         }
    1012                 : #endif
    1013                 :         
    1014            1930 :         if (type) {
    1015            1347 :                 request->conv.last_type = type;
    1016                 :         }
    1017            1930 :         return 0;
    1018                 : }
    1019                 : /* }}} */
    1020                 : 
    1021                 : /* {{{ static inline zval *http_request_option(http_request *, HashTable *, char *, size_t, int) */
    1022                 : static inline zval *_http_request_option_ex(http_request *r, HashTable *options, char *key, size_t keylen, int type TSRMLS_DC)
    1023            2694 : {
    1024            2694 :         if (options) {
    1025                 :                 zval **zoption;
    1026            1766 :                 ulong h = zend_hash_func(key, keylen);
    1027                 :                 
    1028            1766 :                 if (SUCCESS == zend_hash_quick_find(options, key, keylen, h, (void *) &zoption)) {
    1029             258 :                         return http_request_option_cache_ex(r, key, keylen, h, zval_copy(type, *zoption));
    1030                 :                 }
    1031                 :         }
    1032                 :         
    1033            2436 :         return NULL;
    1034                 : }
    1035                 : /* }}} */
    1036                 : 
    1037                 : /* {{{ static inline zval *http_request_option_cache(http_request *, char *key, zval *) */
    1038                 : static inline zval *_http_request_option_cache_ex(http_request *r, char *key, size_t keylen, ulong h, zval *opt TSRMLS_DC)
    1039             258 : {
    1040             258 :         ZVAL_ADDREF(opt);
    1041                 :         
    1042             258 :         if (h) {
    1043             258 :                 zend_hash_quick_update(&r->_cache.options, key, keylen, h, &opt, sizeof(zval *), NULL);
    1044                 :         } else {
    1045               0 :                 zend_hash_update(&r->_cache.options, key, keylen, &opt, sizeof(zval *), NULL);
    1046                 :         }
    1047                 :         
    1048             258 :         return opt;
    1049                 : }
    1050                 : /* }}} */
    1051                 : 
    1052                 : #endif /* HTTP_HAVE_CURL */
    1053                 : 
    1054                 : /*
    1055                 :  * Local variables:
    1056                 :  * tab-width: 4
    1057                 :  * c-basic-offset: 4
    1058                 :  * End:
    1059                 :  * vim600: noet sw=4 ts=4 fdm=marker
    1060                 :  * vim<600: noet sw=4 ts=4
    1061                 :  */
    1062                 : 

Generated by: LTP GCOV extension version 1.5