LCOV - code coverage report
Current view: top level - http - php_http_client_curl.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 831 1050 79.1 %
Date: 2014-11-03 12:21:11 Functions: 54 57 94.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2014, Michael Wallner <mike@php.net>            |
      10             :     +--------------------------------------------------------------------+
      11             : */
      12             : 
      13             : #include "php_http_api.h"
      14             : #include "php_http_client.h"
      15             : 
      16             : #if PHP_HTTP_HAVE_CURL
      17             : 
      18             : #if PHP_HTTP_HAVE_EVENT
      19             : #       if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
      20             : #               include <event.h>
      21             : #               define event_base_new event_init
      22             : #               define event_assign(e, b, s, a, cb, d) do {\
      23             :                         event_set(e, s, a, cb, d); \
      24             :                         event_base_set(b, e); \
      25             :                 } while(0)
      26             : #       else
      27             : #               if PHP_HTTP_HAVE_EVENT2
      28             : #                       include <event2/event.h>
      29             : #                       include <event2/event_struct.h>
      30             : #               else
      31             : #                       error "libevent presence is unknown"
      32             : #               endif
      33             : #       endif
      34             : #       ifndef DBG_EVENTS
      35             : #               define DBG_EVENTS 0
      36             : #       endif
      37             : #endif
      38             : 
      39             : #ifdef PHP_HTTP_HAVE_OPENSSL
      40             : #       include <openssl/ssl.h>
      41             : #endif
      42             : #ifdef PHP_HTTP_HAVE_GNUTLS
      43             : #       include <gnutls.h>
      44             : #endif
      45             : 
      46             : typedef struct php_http_client_curl {
      47             :         CURLM *handle;
      48             : 
      49             :         int unfinished;  /* int because of curl_multi_perform() */
      50             : 
      51             : #if PHP_HTTP_HAVE_EVENT
      52             :         struct event_base *evbase;
      53             :         struct event *timeout;
      54             :         unsigned useevents:1;
      55             : #endif
      56             : } php_http_client_curl_t;
      57             : 
      58             : typedef struct php_http_client_curl_handler {
      59             :         CURL *handle;
      60             :         php_resource_factory_t *rf;
      61             :         php_http_client_t *client;
      62             :         php_http_client_progress_state_t progress;
      63             : 
      64             :         php_http_client_enqueue_t queue;
      65             : 
      66             :         struct {
      67             :                 php_http_message_parser_t *parser;
      68             :                 php_http_message_t *message;
      69             :                 php_http_buffer_t *buffer;
      70             :         } request;
      71             : 
      72             :         struct {
      73             :                 php_http_message_parser_t *parser;
      74             :                 php_http_message_t *message;
      75             :                 php_http_buffer_t *buffer;
      76             :         } response;
      77             : 
      78             :         struct {
      79             :                 HashTable cache;
      80             : 
      81             :                 struct curl_slist *headers;
      82             :                 struct curl_slist *resolve;
      83             :                 php_http_buffer_t cookies;
      84             :                 php_http_buffer_t ranges;
      85             : 
      86             :                 long redirects;
      87             :                 unsigned range_request:1;
      88             :                 unsigned encode_cookies:1;
      89             : 
      90             :                 struct {
      91             :                         uint count;
      92             :                         double delay;
      93             :                 } retry;
      94             : 
      95             :         } options;
      96             : 
      97             : } php_http_client_curl_handler_t;
      98             : 
      99             : typedef struct php_http_curle_storage {
     100             :         char *url;
     101             :         char *cookiestore;
     102             :         CURLcode errorcode;
     103             :         char errorbuffer[0x100];
     104             : } php_http_curle_storage_t;
     105             : 
     106         228 : static inline php_http_curle_storage_t *php_http_curle_get_storage(CURL *ch) {
     107         228 :         php_http_curle_storage_t *st = NULL;
     108             : 
     109         228 :         curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st);
     110             : 
     111         228 :         if (!st) {
     112          37 :                 st = pecalloc(1, sizeof(*st), 1);
     113          37 :                 curl_easy_setopt(ch, CURLOPT_PRIVATE, st);
     114          37 :                 curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer);
     115             :         }
     116             : 
     117         228 :         return st;
     118             : }
     119             : 
     120          37 : static void *php_http_curle_ctor(void *opaque, void *init_arg TSRMLS_DC)
     121             : {
     122             :         void *ch;
     123             : 
     124          37 :         if ((ch = curl_easy_init())) {
     125          37 :                 php_http_curle_get_storage(ch);
     126          37 :                 return ch;
     127             :         }
     128           0 :         return NULL;
     129             : }
     130             : 
     131           0 : static void *php_http_curle_copy(void *opaque, void *handle TSRMLS_DC)
     132             : {
     133             :         void *ch;
     134             : 
     135           0 :         if ((ch = curl_easy_duphandle(handle))) {
     136           0 :                 curl_easy_reset(ch);
     137           0 :                 php_http_curle_get_storage(ch);
     138           0 :                 return ch;
     139             :         }
     140           0 :         return NULL;
     141             : }
     142             : 
     143          37 : static void php_http_curle_dtor(void *opaque, void *handle TSRMLS_DC)
     144             : {
     145          37 :         php_http_curle_storage_t *st = php_http_curle_get_storage(handle);
     146             : 
     147          37 :         curl_easy_cleanup(handle);
     148             : 
     149          37 :         if (st) {
     150          37 :                 if (st->url) {
     151          37 :                         pefree(st->url, 1);
     152             :                 }
     153          37 :                 if (st->cookiestore) {
     154           0 :                         pefree(st->cookiestore, 1);
     155             :                 }
     156          37 :                 pefree(st, 1);
     157             :         }
     158          37 : }
     159             : 
     160             : static php_resource_factory_ops_t php_http_curle_resource_factory_ops = {
     161             :         php_http_curle_ctor,
     162             :         php_http_curle_copy,
     163             :         php_http_curle_dtor
     164             : };
     165             : 
     166          29 : static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC)
     167             : {
     168          29 :         return curl_multi_init();
     169             : }
     170             : 
     171          29 : static void php_http_curlm_dtor(void *opaque, void *handle TSRMLS_DC)
     172             : {
     173          29 :         curl_multi_cleanup(handle);
     174          29 : }
     175             : 
     176             : static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = {
     177             :         php_http_curlm_ctor,
     178             :         NULL,
     179             :         php_http_curlm_dtor
     180             : };
     181             : 
     182             : /* curl callbacks */
     183             : 
     184           3 : static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, void *ctx)
     185             : {
     186           3 :         php_http_message_body_t *body = ctx;
     187             : 
     188           3 :         if (body && body->stream_id) {
     189           3 :                 php_stream *s = php_http_message_body_stream(body);
     190             : 
     191           3 :                 if (s) {
     192             :                         TSRMLS_FETCH_FROM_CTX(body->ts);
     193           3 :                         return php_stream_read(s, data, len * n);
     194           0 :                 } else abort();
     195             :         }
     196           0 :         return 0;
     197             : }
     198             : 
     199             : #if PHP_HTTP_CURL_VERSION(7,32,0)
     200        2292 : static int php_http_curle_xferinfo_callback(void *ctx, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
     201             : #else
     202             : static int php_http_curle_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
     203             : #endif
     204             : {
     205        2292 :         php_http_client_curl_handler_t *h = ctx;
     206        2292 :         zend_bool update = 0;
     207             : 
     208        2292 :         if (h->progress.dl.total != dltotal
     209        2276 :         ||      h->progress.dl.now != dlnow
     210        2246 :         ||      h->progress.ul.total != ultotal
     211        2243 :         ||      h->progress.ul.now != ulnow
     212             :         ) {
     213          52 :                 update = 1;
     214             : 
     215          52 :                 h->progress.dl.total = dltotal;
     216          52 :                 h->progress.dl.now = dlnow;
     217          52 :                 h->progress.ul.total = ultotal;
     218          52 :                 h->progress.ul.now = ulnow;
     219             :         }
     220             : 
     221        2292 :         if (update && h->client->callback.progress.func) {
     222          52 :                 h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
     223             :         }
     224             : 
     225        2292 :         return 0;
     226             : }
     227             : 
     228           0 : static curlioerr php_http_curle_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx)
     229             : {
     230           0 :         php_http_message_body_t *body = ctx;
     231             : 
     232           0 :         if (cmd != CURLIOCMD_RESTARTREAD) {
     233           0 :                 return CURLIOE_UNKNOWNCMD;
     234             :         }
     235             : 
     236           0 :         if (body) {
     237             :                 TSRMLS_FETCH_FROM_CTX(body->ts);
     238             : 
     239           0 :                 if (SUCCESS == php_stream_rewind(php_http_message_body_stream(body))) {
     240           0 :                         return CURLIOE_OK;
     241             :                 }
     242             :         }
     243             : 
     244           0 :         return CURLIOE_FAILRESTART;
     245             : }
     246             : 
     247         573 : static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
     248             : {
     249         573 :         php_http_client_curl_handler_t *h = ctx;
     250         573 :         unsigned flags = 0;
     251             : 
     252             :         /* catch progress */
     253         573 :         switch (type) {
     254             :                 case CURLINFO_TEXT:
     255         190 :                         if (data[0] == '-') {
     256         190 :                         } else if (php_memnstr(data, ZEND_STRL("Adding handle:"), data + length)) {
     257           0 :                                 h->progress.info = "setup";
     258         190 :                         } else if (php_memnstr(data, ZEND_STRL("addHandle"), data + length)) {
     259           0 :                                 h->progress.info = "setup";
     260         190 :                         } else if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) {
     261           0 :                                 h->progress.info = "resolve";
     262         190 :                         } else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) {
     263          20 :                                 h->progress.info = "connect";
     264         170 :                         } else if (php_memnstr(data, ZEND_STRL("Found bundle for host"), data + length)) {
     265           6 :                                 h->progress.info = "connect";
     266         164 :                         } else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) {
     267          24 :                                 h->progress.info = "connected";
     268         140 :                         } else if (php_memnstr(data, ZEND_STRL("Re-using existing connection!"), data + length)) {
     269           4 :                                 h->progress.info = "connected";
     270         136 :                         } else if (php_memnstr(data, ZEND_STRL("blacklisted"), data + length)) {
     271          24 :                                 h->progress.info = "blacklist check";
     272         112 :                         } else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) {
     273          26 :                                 h->progress.info = "ssl negotiation";
     274          86 :                         } else if (php_memnstr(data, ZEND_STRL("upload"), data + length)) {
     275           3 :                                 h->progress.info = "uploaded";
     276          83 :                         } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) {
     277          23 :                                 h->progress.info = "not disconnected";
     278          60 :                         } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) {
     279           0 :                                 h->progress.info = "disconnected";
     280          60 :                         } else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) {
     281           0 :                                 h->progress.info = "redirect";
     282          60 :                         } else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) {
     283           0 :                                 h->progress.info = "timeout";
     284             :                         } else {
     285             : #if 0
     286             :                                 h->progress.info = data;
     287             :                                 data[length - 1] = '\0';
     288             : #endif
     289             :                         }
     290         190 :                         if (h->client->callback.progress.func) {
     291         190 :                                 h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
     292             :                         }
     293         190 :                         break;
     294             :                 case CURLINFO_HEADER_OUT:
     295             :                 case CURLINFO_DATA_OUT:
     296             :                 case CURLINFO_SSL_DATA_OUT:
     297          36 :                         h->progress.info = "send";
     298          36 :                         break;
     299             :                 case CURLINFO_HEADER_IN:
     300             :                 case CURLINFO_DATA_IN:
     301             :                 case CURLINFO_SSL_DATA_IN:
     302         347 :                         h->progress.info = "receive";
     303         347 :                         break;
     304             :                 default:
     305           0 :                         break;
     306             :         }
     307             :         /* process data */
     308         573 :         switch (type) {
     309             :                 case CURLINFO_HEADER_IN:
     310             :                 case CURLINFO_DATA_IN:
     311         335 :                         php_http_buffer_append(h->response.buffer, data, length);
     312             : 
     313         335 :                         if (h->options.redirects) {
     314           0 :                                 flags |= PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS;
     315             :                         }
     316             : 
     317         335 :                         if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->response.parser, h->response.buffer, flags, &h->response.message)) {
     318           0 :                                 return -1;
     319             :                         }
     320         335 :                         break;
     321             : 
     322             :                 case CURLINFO_HEADER_OUT:
     323             :                 case CURLINFO_DATA_OUT:
     324          27 :                         php_http_buffer_append(h->request.buffer, data, length);
     325             : 
     326          27 :                         if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->request.parser, h->request.buffer, flags, &h->request.message)) {
     327           0 :                                 return -1;
     328             :                         }
     329          27 :                         break;
     330             :                 default:
     331         211 :                         break;
     332             :         }
     333             : 
     334             : #if 0
     335             :         /* debug */
     336             :         _dpf(type, data, length);
     337             : #endif
     338             : 
     339         573 :         return 0;
     340             : }
     341             : 
     342          42 : static int php_http_curle_dummy_callback(char *data, size_t n, size_t l, void *s)
     343             : {
     344          42 :         return n*l;
     345             : }
     346             : 
     347          25 : static STATUS php_http_curle_get_info(CURL *ch, HashTable *info)
     348             : {
     349             :         char *c;
     350             :         long l;
     351             :         double d;
     352             :         struct curl_slist *s, *p;
     353             :         zval *subarray, array;
     354          25 :         INIT_PZVAL_ARRAY(&array, info);
     355             : 
     356             :         /* BEGIN::CURLINFO */
     357          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) {
     358          25 :                 add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1);
     359             :         }
     360          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) {
     361          25 :                 add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l);
     362             :         }
     363          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) {
     364          25 :                 add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d);
     365             :         }
     366          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) {
     367          25 :                 add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d);
     368             :         }
     369          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) {
     370          25 :                 add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d);
     371             :         }
     372          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) {
     373          25 :                 add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d);
     374             :         }
     375          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) {
     376          25 :                 add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d);
     377             :         }
     378          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) {
     379          25 :                 add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d);
     380             :         }
     381          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) {
     382          25 :                 add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d);
     383             :         }
     384          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) {
     385          25 :                 add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d);
     386             :         }
     387          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) {
     388          25 :                 add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l);
     389             :         }
     390          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) {
     391          25 :                 add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l);
     392             :         }
     393          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) {
     394          25 :                 add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l);
     395             :         }
     396          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) {
     397          25 :                 add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l);
     398             :         }
     399          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
     400          25 :                 add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d);
     401             :         }
     402          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) {
     403          25 :                 add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d);
     404             :         }
     405          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) {
     406          25 :                 add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d);
     407             :         }
     408          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) {
     409          25 :                 add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1);
     410             :         }
     411          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) {
     412          25 :                 add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d);
     413             :         }
     414          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) {
     415          25 :                 add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l);
     416             :         }
     417          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) {
     418          25 :                 add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l);
     419             :         }
     420          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) {
     421          25 :                 add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l);
     422             :         }
     423          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) {
     424          25 :                 add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l);
     425             :         }
     426          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) {
     427          25 :                 add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l);
     428             :         }
     429          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) {
     430          25 :                 add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l);
     431             :         }
     432          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) {
     433          25 :                 MAKE_STD_ZVAL(subarray);
     434          25 :                 array_init(subarray);
     435         100 :                 for (p = s; p; p = p->next) {
     436          75 :                         if (p->data) {
     437          75 :                                 add_next_index_string(subarray, p->data, 1);
     438             :                         }
     439             :                 }
     440          25 :                 add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray);
     441          25 :                 curl_slist_free_all(s);
     442             :         }
     443          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_COOKIELIST, &s)) {
     444          25 :                 MAKE_STD_ZVAL(subarray);
     445          25 :                 array_init(subarray);
     446          36 :                 for (p = s; p; p = p->next) {
     447          11 :                         if (p->data) {
     448          11 :                                 add_next_index_string(subarray, p->data, 1);
     449             :                         }
     450             :                 }
     451          25 :                 add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray);
     452          25 :                 curl_slist_free_all(s);
     453             :         }
     454          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) {
     455          25 :                 add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1);
     456             :         }
     457             : #if PHP_HTTP_CURL_VERSION(7,19,0)
     458          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) {
     459          25 :                 add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1);
     460             :         }
     461             : #endif
     462             : #if PHP_HTTP_CURL_VERSION(7,19,0)
     463          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) {
     464          25 :                 add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d);
     465             :         }
     466             : #endif
     467             : #if PHP_HTTP_CURL_VERSION(7,19,4)
     468          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) {
     469          25 :                 add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l);
     470             :         }
     471             : #endif
     472             : #if PHP_HTTP_CURL_VERSION(7,21,0)
     473          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) {
     474          25 :                 add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l);
     475             :         }
     476             : #endif
     477             : #if PHP_HTTP_CURL_VERSION(7,21,0)
     478          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) {
     479          25 :                 add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1);
     480             :         }
     481             : #endif
     482             : #if PHP_HTTP_CURL_VERSION(7,21,0)
     483          25 :         if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) {
     484          25 :                 add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l);
     485             :         }
     486             : #endif
     487             : 
     488             :         /* END::CURLINFO */
     489             : 
     490             : #if PHP_HTTP_CURL_VERSION(7,34,0)
     491             :         {
     492             :                 zval *ti_array;
     493             :                 struct curl_tlssessioninfo *ti;
     494             : 
     495          25 :                 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SESSION, &ti)) {
     496             :                         const char *backend;
     497             : 
     498          25 :                         MAKE_STD_ZVAL(subarray);
     499          25 :                         ZVAL_NULL(subarray);
     500          25 :                         MAKE_STD_ZVAL(ti_array);
     501          25 :                         array_init(ti_array);
     502             : 
     503          25 :                         switch (ti->backend) {
     504             :                         case CURLSSLBACKEND_NONE:
     505          25 :                                 backend = "none";
     506          25 :                                 break;
     507             :                         case CURLSSLBACKEND_OPENSSL:
     508           0 :                                 backend = "openssl";
     509             : #ifdef PHP_HTTP_HAVE_OPENSSL
     510             :                                 {
     511           0 :                                         SSL_CTX *ctx = ti->internals;
     512             : 
     513           0 :                                         array_init(subarray);
     514           0 :                                         add_assoc_long_ex(subarray, ZEND_STRS("number"), SSL_CTX_sess_number(ctx));
     515           0 :                                         add_assoc_long_ex(subarray, ZEND_STRS("connect"), SSL_CTX_sess_connect(ctx));
     516           0 :                                         add_assoc_long_ex(subarray, ZEND_STRS("connect_good"), SSL_CTX_sess_connect_good(ctx));
     517           0 :                                         add_assoc_long_ex(subarray, ZEND_STRS("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx));
     518           0 :                                         add_assoc_long_ex(subarray, ZEND_STRS("hits"), SSL_CTX_sess_hits(ctx));
     519           0 :                                         add_assoc_long_ex(subarray, ZEND_STRS("cache_full"), SSL_CTX_sess_cache_full(ctx));
     520             :                                 }
     521             : #endif
     522           0 :                                 break;
     523             :                         case CURLSSLBACKEND_GNUTLS:
     524           0 :                                 backend = "gnutls";
     525             : #ifdef PHP_HTTP_HAVE_GNUTLS
     526             :                                 {
     527             :                                         gnutls_session_t sess = ti->internals;
     528             :                                         char *desc;
     529             : 
     530             :                                         array_init(subarray);
     531             :                                         if ((desc = gnutls_session_get_desc(sess))) {
     532             :                                                 add_assoc_string_ex(subarray, ZEND_STRS("desc"), desc, 1);
     533             :                                                 gnutls_free(desc);
     534             :                                         }
     535             :                                         add_assoc_bool_ex(subarray, ZEND_STRS("resumed"), gnutls_session_is_resumed(sess));
     536             :                                 }
     537             : #endif
     538           0 :                                 break;
     539             :                         case CURLSSLBACKEND_NSS:
     540           0 :                                 backend = "nss";
     541           0 :                                 break;
     542             :                         case CURLSSLBACKEND_QSOSSL:
     543           0 :                                 backend = "qsossl";
     544           0 :                                 break;
     545             :                         case CURLSSLBACKEND_GSKIT:
     546           0 :                                 backend = "gskit";
     547           0 :                                 break;
     548             :                         case CURLSSLBACKEND_POLARSSL:
     549           0 :                                 backend = "polarssl";
     550           0 :                                 break;
     551             :                         case CURLSSLBACKEND_CYASSL:
     552           0 :                                 backend = "cyassl";
     553           0 :                                 break;
     554             :                         case CURLSSLBACKEND_SCHANNEL:
     555           0 :                                 backend = "schannel";
     556           0 :                                 break;
     557             :                         case CURLSSLBACKEND_DARWINSSL:
     558           0 :                                 backend = "darwinssl";
     559           0 :                                 break;
     560             :                         default:
     561           0 :                                 backend = "unknown";
     562             :                         }
     563          25 :                         add_assoc_string_ex(ti_array, ZEND_STRS("backend"), estrdup(backend), 0);
     564          25 :                         add_assoc_zval_ex(ti_array, ZEND_STRS("internals"), subarray);
     565          25 :                         add_assoc_zval_ex(&array, "tls_session", sizeof("tls_session"), ti_array);
     566             :                 }
     567             :         }
     568             : #endif
     569             : 
     570             : #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
     571             :         {
     572             :                 int i;
     573             :                 zval *ci_array;
     574             :                 struct curl_certinfo *ci;
     575             :                 char *colon, *keyname;
     576             : 
     577          25 :                 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) {
     578          25 :                         MAKE_STD_ZVAL(ci_array);
     579          25 :                         array_init(ci_array);
     580             : 
     581          25 :                         for (i = 0; i < ci->num_of_certs; ++i) {
     582           0 :                                 s = ci->certinfo[i];
     583             : 
     584           0 :                                 MAKE_STD_ZVAL(subarray);
     585           0 :                                 array_init(subarray);
     586           0 :                                 for (p = s; p; p = p->next) {
     587           0 :                                         if (p->data) {
     588           0 :                                                 if ((colon = strchr(p->data, ':'))) {
     589           0 :                                                         keyname = estrndup(p->data, colon - p->data);
     590           0 :                                                         add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1);
     591           0 :                                                         efree(keyname);
     592             :                                                 } else {
     593           0 :                                                         add_next_index_string(subarray, p->data, 1);
     594             :                                                 }
     595             :                                         }
     596             :                                 }
     597           0 :                                 add_next_index_zval(ci_array, subarray);
     598             :                         }
     599          25 :                         add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array);
     600             :                 }
     601             :         }
     602             : #endif
     603             :         {
     604          25 :                 php_http_curle_storage_t *st = php_http_curle_get_storage(ch);
     605             : 
     606          25 :                 add_assoc_long_ex(&array, "curlcode", sizeof("curlcode"), st->errorcode);
     607          25 :                 add_assoc_string_ex(&array, "error", sizeof("error"), st->errorbuffer, 1);
     608             :         }
     609             : 
     610          25 :         return SUCCESS;
     611             : }
     612             : 
     613          70 : static int compare_queue(php_http_client_enqueue_t *e, void *handle)
     614             : {
     615          70 :         return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle;
     616             : }
     617             : 
     618        2022 : static void php_http_curlm_responsehandler(php_http_client_t *context)
     619             : {
     620        2022 :         int remaining = 0;
     621             :         php_http_client_enqueue_t *enqueue;
     622        2022 :         php_http_client_curl_t *curl = context->ctx;
     623             :         TSRMLS_FETCH_FROM_CTX(context->ts);
     624             : 
     625             :         do {
     626        2022 :                 CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining);
     627             : 
     628        2022 :                 if (msg && CURLMSG_DONE == msg->msg) {
     629          24 :                         if (CURLE_OK != msg->data.result) {
     630           0 :                                 php_http_curle_storage_t *st = php_http_curle_get_storage(msg->easy_handle);
     631           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s; %s (%s)", curl_easy_strerror(st->errorcode = msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url));
     632             :                         }
     633             : 
     634          24 :                         if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) {
     635          24 :                                 php_http_client_curl_handler_t *handler = enqueue->opaque;
     636             : 
     637          24 :                                 context->callback.response.func(context->callback.response.arg, context, &handler->queue, &handler->request.message, &handler->response.message);
     638             :                         }
     639             :                 }
     640        2022 :         } while (remaining);
     641        2022 : }
     642             : 
     643             : #if PHP_HTTP_HAVE_EVENT
     644             : 
     645             : typedef struct php_http_curlm_event {
     646             :         struct event evnt;
     647             :         php_http_client_t *context;
     648             : } php_http_curlm_event_t;
     649             : 
     650          17 : static inline int etoca(short action) {
     651          17 :         switch (action & (EV_READ|EV_WRITE)) {
     652             :                 case EV_READ:
     653          12 :                         return CURL_CSELECT_IN;
     654             :                         break;
     655             :                 case EV_WRITE:
     656           5 :                         return CURL_CSELECT_OUT;
     657             :                         break;
     658             :                 case EV_READ|EV_WRITE:
     659           0 :                         return CURL_CSELECT_IN|CURL_CSELECT_OUT;
     660             :                         break;
     661             :                 default:
     662           0 :                         return 0;
     663             :         }
     664             : }
     665             : 
     666          19 : static void php_http_curlm_timeout_callback(int socket, short action, void *event_data)
     667             : {
     668          19 :         php_http_client_t *context = event_data;
     669          19 :         php_http_client_curl_t *curl = context->ctx;
     670             : 
     671             : #if DBG_EVENTS
     672             :         fprintf(stderr, "T");
     673             : #endif
     674          19 :         if (curl->useevents) {
     675             :                 CURLMcode rc;
     676             :                 TSRMLS_FETCH_FROM_CTX(context->ts);
     677             : 
     678             :                 /* ignore and use -1,0 on timeout */
     679             :                 (void) socket;
     680             :                 (void) action;
     681             : 
     682          19 :                 while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished)));
     683             : 
     684          19 :                 if (CURLM_OK != rc) {
     685           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s",  curl_multi_strerror(rc));
     686             :                 }
     687             : 
     688          19 :                 php_http_curlm_responsehandler(context);
     689             :         }
     690          19 : }
     691             : 
     692          17 : static void php_http_curlm_event_callback(int socket, short action, void *event_data)
     693             : {
     694          17 :         php_http_client_t *context = event_data;
     695          17 :         php_http_client_curl_t *curl = context->ctx;
     696             : 
     697             : #if DBG_EVENTS
     698             :         fprintf(stderr, "E");
     699             : #endif
     700          17 :         if (curl->useevents) {
     701          17 :                 CURLMcode rc = CURLM_OK;
     702             :                 TSRMLS_FETCH_FROM_CTX(context->ts);
     703             : 
     704          17 :                 while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished)));
     705             : 
     706          17 :                 if (CURLM_OK != rc) {
     707           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
     708             :                 }
     709             : 
     710          17 :                 php_http_curlm_responsehandler(context);
     711             : 
     712             :                 /* remove timeout if there are no transfers left */
     713          17 :                 if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
     714           3 :                         event_del(curl->timeout);
     715             :                 }
     716             :         }
     717          17 : }
     718             : 
     719          15 : static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
     720             : {
     721          15 :         php_http_client_t *context = socket_data;
     722          15 :         php_http_client_curl_t *curl = context->ctx;
     723             : 
     724             : #if DBG_EVENTS
     725             :         fprintf(stderr, "S");
     726             : #endif
     727          15 :         if (curl->useevents) {
     728          15 :                 int events = EV_PERSIST;
     729          15 :                 php_http_curlm_event_t *ev = assign_data;
     730             :                 TSRMLS_FETCH_FROM_CTX(context->ts);
     731             : 
     732          15 :                 if (!ev) {
     733           5 :                         ev = ecalloc(1, sizeof(php_http_curlm_event_t));
     734           5 :                         ev->context = context;
     735           5 :                         curl_multi_assign(curl->handle, sock, ev);
     736             :                 } else {
     737          10 :                         event_del(&ev->evnt);
     738             :                 }
     739             : 
     740          15 :                 switch (action) {
     741             :                         case CURL_POLL_IN:
     742           5 :                                 events |= EV_READ;
     743           5 :                                 break;
     744             :                         case CURL_POLL_OUT:
     745           5 :                                 events |= EV_WRITE;
     746           5 :                                 break;
     747             :                         case CURL_POLL_INOUT:
     748           0 :                                 events |= EV_READ|EV_WRITE;
     749           0 :                                 break;
     750             : 
     751             :                         case CURL_POLL_REMOVE:
     752           5 :                                 efree(ev);
     753             :                                 /* no break */
     754             :                         case CURL_POLL_NONE:
     755           5 :                                 return 0;
     756             : 
     757             :                         default:
     758           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
     759           0 :                                 return -1;
     760             :                 }
     761             : 
     762          10 :                 event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context);
     763          10 :                 event_add(&ev->evnt, NULL);
     764             :         }
     765             : 
     766          10 :         return 0;
     767             : }
     768             : 
     769          25 : static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
     770             : {
     771          25 :         php_http_client_t *context = timer_data;
     772          25 :         php_http_client_curl_t *curl = context->ctx;
     773             : 
     774             : #if DBG_EVENTS
     775             :         fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
     776             : #endif
     777          25 :         if (curl->useevents) {
     778             : 
     779          25 :                 if (timeout_ms < 0) {
     780           4 :                         php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context);
     781          21 :                 } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
     782             :                         struct timeval timeout;
     783             : 
     784          21 :                         if (!event_initialized(curl->timeout)) {
     785           4 :                                 event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context);
     786             :                         }
     787             : 
     788          21 :                         timeout.tv_sec = timeout_ms / 1000;
     789          21 :                         timeout.tv_usec = (timeout_ms % 1000) * 1000;
     790             : 
     791          21 :                         event_add(curl->timeout, &timeout);
     792             :                 }
     793             :         }
     794          25 : }
     795             : 
     796             : #endif /* HAVE_EVENT */
     797             : 
     798             : /* curl options */
     799             : 
     800             : static php_http_options_t php_http_curle_options;
     801             : 
     802             : #define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN              0x0001
     803             : #define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR             0x0002
     804             : #define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS              0x0004
     805             : 
     806           1 : static STATUS php_http_curle_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata)
     807             : {
     808           1 :         php_http_client_curl_handler_t *curl = userdata;
     809           1 :         CURL *ch = curl->handle;
     810             : 
     811           1 :         if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_BVAL_P(val) ? 2 : 0)) {
     812           0 :                 return FAILURE;
     813             :         }
     814           1 :         return SUCCESS;
     815             : }
     816             : 
     817          43 : static STATUS php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata)
     818             : {
     819          43 :         php_http_client_curl_handler_t *curl = userdata;
     820          43 :         CURL *ch = curl->handle;
     821          43 :         php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle);
     822             : 
     823          43 :         if (storage->cookiestore) {
     824           0 :                 pefree(storage->cookiestore, 1);
     825             :         }
     826          43 :         if (val && Z_STRLEN_P(val)) {
     827           0 :                 storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1);
     828             :         } else {
     829          43 :                 storage->cookiestore = NULL;
     830             :         }
     831          43 :         if (    CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore)
     832          43 :                 ||      CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)
     833             :         ) {
     834           0 :                 return FAILURE;
     835             :         }
     836          43 :         return SUCCESS;
     837             : }
     838             : 
     839          43 : static STATUS php_http_curle_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata)
     840             : {
     841          43 :         php_http_client_curl_handler_t *curl = userdata;
     842          43 :         CURL *ch = curl->handle;
     843             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
     844             : 
     845          43 :         if (val && Z_TYPE_P(val) != IS_NULL) {
     846           4 :                 if (curl->options.encode_cookies) {
     847           2 :                         if (SUCCESS == php_http_url_encode_hash_ex(HASH_OF(val), &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0 TSRMLS_CC)) {
     848           2 :                                 php_http_buffer_fix(&curl->options.cookies);
     849           2 :                                 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) {
     850           0 :                                         return FAILURE;
     851             :                                 }
     852             :                         } else {
     853           0 :                                 return FAILURE;
     854             :                         }
     855             :                 } else {
     856             :                         HashPosition pos;
     857           0 :                         php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0);
     858             :                         zval **cookie_val;
     859             : 
     860           0 :                         FOREACH_KEYVAL(pos, val, cookie_key, cookie_val) {
     861           0 :                                 zval *zv = php_http_ztyp(IS_STRING, *cookie_val);
     862             : 
     863           0 :                                 php_http_array_hashkey_stringify(&cookie_key);
     864           0 :                                 php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(zv));
     865           0 :                                 php_http_array_hashkey_stringfree(&cookie_key);
     866             : 
     867           0 :                                 zval_ptr_dtor(&zv);
     868             :                         }
     869             : 
     870           0 :                         php_http_buffer_fix(&curl->options.cookies);
     871           0 :                         if (curl->options.cookies.used) {
     872           0 :                                 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) {
     873           0 :                                         return FAILURE;
     874             :                                 }
     875             :                         }
     876             :                 }
     877             :         } else {
     878          41 :                 php_http_buffer_reset(&curl->options.cookies);
     879          41 :                 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, NULL)) {
     880           0 :                         return FAILURE;
     881             :                 }
     882             :         }
     883          43 :         return SUCCESS;
     884             : }
     885             : 
     886          43 : static STATUS php_http_curle_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata)
     887             : {
     888          43 :         php_http_client_curl_handler_t *curl = userdata;
     889             : 
     890          43 :         curl->options.encode_cookies = Z_BVAL_P(val);
     891          43 :         return SUCCESS;
     892             : }
     893             : 
     894          43 : static STATUS php_http_curle_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata)
     895             : {
     896          43 :         php_http_client_curl_handler_t *curl = userdata;
     897          43 :         CURL *ch = curl->handle;
     898             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
     899             : 
     900          43 :         if (Z_LVAL_P(val)) {
     901           0 :                 if (Z_LVAL_P(val) > 0) {
     902           0 :                         if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) {
     903           0 :                                 return FAILURE;
     904             :                         }
     905             :                 } else {
     906           0 :                         if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) sapi_get_request_time(TSRMLS_C) + Z_LVAL_P(val))) {
     907           0 :                                 return FAILURE;
     908             :                         }
     909             :                 }
     910           0 :                 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) {
     911           0 :                         return FAILURE;
     912             :                 }
     913             :         } else {
     914          43 :                 if (    CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0)
     915          43 :                         ||      CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0)
     916             :                 ) {
     917           0 :                         return FAILURE;
     918             :                 }
     919             :         }
     920          43 :         return SUCCESS;
     921             : }
     922             : 
     923          43 : static STATUS php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata)
     924             : {
     925          43 :         php_http_client_curl_handler_t *curl = userdata;
     926             : 
     927          43 :         if (Z_BVAL_P(val)) {
     928           0 :                 curl->options.headers = curl_slist_append(curl->options.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5");
     929             :         }
     930          43 :         return SUCCESS;
     931             : }
     932             : 
     933          43 : static STATUS php_http_curle_option_set_etag(php_http_option_t *opt, zval *val, void *userdata)
     934             : {
     935          43 :         php_http_client_curl_handler_t *curl = userdata;
     936             :         php_http_buffer_t header;
     937             : 
     938          43 :         if (Z_STRLEN_P(val)) {
     939           0 :                 zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"'));
     940           0 :                 php_http_buffer_init(&header);
     941           0 :                 php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val));
     942           0 :                 php_http_buffer_fix(&header);
     943           0 :                 curl->options.headers = curl_slist_append(curl->options.headers, header.data);
     944           0 :                 php_http_buffer_dtor(&header);
     945             :         }
     946          43 :         return SUCCESS;
     947             : }
     948             : 
     949          43 : static STATUS php_http_curle_option_set_range(php_http_option_t *opt, zval *val, void *userdata)
     950             : {
     951          43 :         php_http_client_curl_handler_t *curl = userdata;
     952          43 :         CURL *ch = curl->handle;
     953             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
     954             : 
     955          43 :         php_http_buffer_reset(&curl->options.ranges);
     956             : 
     957          43 :         if (val && Z_TYPE_P(val) != IS_NULL) {
     958             :                 HashPosition pos;
     959             :                 zval **rr, **rb, **re;
     960             : 
     961           0 :                 FOREACH_VAL(pos, val, rr) {
     962           0 :                         if (Z_TYPE_PP(rr) == IS_ARRAY) {
     963           0 :                                 if (2 == php_http_array_list(Z_ARRVAL_PP(rr) TSRMLS_CC, 2, &rb, &re)) {
     964           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))) &&
     965           0 :                                                         ((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)))) {
     966           0 :                                                 zval *rbl = php_http_ztyp(IS_LONG, *rb);
     967           0 :                                                 zval *rel = php_http_ztyp(IS_LONG, *re);
     968             : 
     969           0 :                                                 if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) {
     970           0 :                                                         php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel));
     971             :                                                 }
     972           0 :                                                 zval_ptr_dtor(&rbl);
     973           0 :                                                 zval_ptr_dtor(&rel);
     974             :                                         }
     975             : 
     976             :                                 }
     977             :                         }
     978             :                 }
     979             : 
     980           0 :                 if (curl->options.ranges.used) {
     981           0 :                         curl->options.range_request = 1;
     982             :                         /* ditch last comma */
     983           0 :                         curl->options.ranges.data[curl->options.ranges.used - 1] = '\0';
     984             :                 }
     985             :         }
     986             : 
     987          43 :         if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) {
     988           0 :                 return FAILURE;
     989             :         }
     990          43 :         return SUCCESS;
     991             : }
     992             : 
     993          43 : static STATUS php_http_curle_option_set_resume(php_http_option_t *opt, zval *val, void *userdata)
     994             : {
     995          43 :         php_http_client_curl_handler_t *curl = userdata;
     996          43 :         CURL *ch = curl->handle;
     997             : 
     998          43 :         if (Z_LVAL_P(val) > 0) {
     999           0 :                 curl->options.range_request = 1;
    1000             :         }
    1001          43 :         if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) {
    1002           0 :                 return FAILURE;
    1003             :         }
    1004          43 :         return SUCCESS;
    1005             : }
    1006             : 
    1007          43 : static STATUS php_http_curle_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata)
    1008             : {
    1009          43 :         php_http_client_curl_handler_t *curl = userdata;
    1010             : 
    1011          43 :         curl->options.retry.delay = Z_DVAL_P(val);
    1012          43 :         return SUCCESS;
    1013             : }
    1014             : 
    1015          43 : static STATUS php_http_curle_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata)
    1016             : {
    1017          43 :         php_http_client_curl_handler_t *curl = userdata;
    1018             : 
    1019          43 :         curl->options.retry.count = Z_LVAL_P(val);
    1020          43 :         return SUCCESS;
    1021             : }
    1022             : 
    1023          43 : static STATUS php_http_curle_option_set_redirect(php_http_option_t *opt, zval *val, void *userdata)
    1024             : {
    1025          43 :         php_http_client_curl_handler_t *curl = userdata;
    1026          43 :         CURL *ch = curl->handle;
    1027             : 
    1028          43 :         if (    CURLE_OK != curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L)
    1029          43 :                 ||      CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val))
    1030             :         ) {
    1031           0 :                 return FAILURE;
    1032             :         }
    1033          43 :         return SUCCESS;
    1034             : }
    1035             : 
    1036          43 : static STATUS php_http_curle_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata)
    1037             : {
    1038          43 :         php_http_client_curl_handler_t *curl = userdata;
    1039          43 :         CURL *ch = curl->handle;
    1040          43 :         long localport = 0, localportrange = 0;
    1041             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
    1042             : 
    1043          43 :         if (val && Z_TYPE_P(val) != IS_NULL) {
    1044           0 :                 zval **z_port_start, *zps_copy = NULL, **z_port_end, *zpe_copy = NULL;
    1045             : 
    1046           0 :                 switch (php_http_array_list(Z_ARRVAL_P(val) TSRMLS_CC, 2, &z_port_start, &z_port_end)) {
    1047             :                 case 2:
    1048           0 :                         zps_copy = php_http_ztyp(IS_LONG, *z_port_start);
    1049           0 :                         zpe_copy = php_http_ztyp(IS_LONG, *z_port_end);
    1050           0 :                         localportrange = labs(Z_LVAL_P(zps_copy)-Z_LVAL_P(zpe_copy))+1L;
    1051             :                         /* no break */
    1052             :                 case 1:
    1053           0 :                         if (!zps_copy) {
    1054           0 :                                 zps_copy = php_http_ztyp(IS_LONG, *z_port_start);
    1055             :                         }
    1056           0 :                         localport = (zpe_copy && Z_LVAL_P(zpe_copy) > 0) ? MIN(Z_LVAL_P(zps_copy), Z_LVAL_P(zpe_copy)) : Z_LVAL_P(zps_copy);
    1057           0 :                         zval_ptr_dtor(&zps_copy);
    1058           0 :                         if (zpe_copy) {
    1059           0 :                                 zval_ptr_dtor(&zpe_copy);
    1060             :                         }
    1061           0 :                         break;
    1062             :                 default:
    1063           0 :                         break;
    1064             :                 }
    1065             :         }
    1066          43 :         if (    CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport)
    1067          43 :                 ||      CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange)
    1068             :         ) {
    1069           0 :                 return FAILURE;
    1070             :         }
    1071          43 :         return SUCCESS;
    1072             : }
    1073             : 
    1074             : #if PHP_HTTP_CURL_VERSION(7,21,3)
    1075          43 : static STATUS php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata)
    1076             : {
    1077          43 :         php_http_client_curl_handler_t *curl = userdata;
    1078          43 :         CURL *ch = curl->handle;
    1079             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
    1080             : 
    1081          43 :         if (val && Z_TYPE_P(val) != IS_NULL) {
    1082           0 :                 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
    1083             :                 HashPosition pos;
    1084             :                 zval **data;
    1085             : 
    1086           0 :                 FOREACH_KEYVAL(pos, val, key, data) {
    1087           0 :                         zval *cpy = php_http_ztyp(IS_STRING, *data);
    1088           0 :                         curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy));
    1089           0 :                         zval_ptr_dtor(&cpy);
    1090             :                 }
    1091             : 
    1092           0 :                 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) {
    1093           0 :                         return FAILURE;
    1094             :                 }
    1095             :         } else {
    1096          43 :                 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) {
    1097           0 :                         return FAILURE;
    1098             :                 }
    1099             :         }
    1100          43 :         return SUCCESS;
    1101             : }
    1102             : #endif
    1103             : 
    1104         408 : static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC)
    1105             : {
    1106             :         php_http_option_t *opt;
    1107             : 
    1108             :         /* proxy */
    1109         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) {
    1110         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1111             :         }
    1112         408 :         php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG);
    1113         408 :         php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG);
    1114         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) {
    1115         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1116             :         }
    1117         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG))) {
    1118         408 :                 Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
    1119             :         }
    1120         408 :         php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL);
    1121             : #if PHP_HTTP_CURL_VERSION(7,19,4)
    1122         408 :         php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING);
    1123             : #endif
    1124             : 
    1125             :         /* dns */
    1126         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) {
    1127         408 :                 Z_LVAL(opt->defval) = 60;
    1128             :         }
    1129         408 :         php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG);
    1130             : #if PHP_HTTP_CURL_VERSION(7,21,3)
    1131         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) {
    1132         408 :                 opt->setter = php_http_curle_option_set_resolve;
    1133             :         }
    1134             : #endif
    1135             : #if PHP_HTTP_HAVE_ARES
    1136             : # if PHP_HTTP_CURL_VERSION(7,24,0)
    1137             :         if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) {
    1138             :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1139             :         }
    1140             : # endif
    1141             : # if PHP_HTTP_CURL_VERSION(7,33,0)
    1142             :         if ((opt = php_http_option_register(registry, ZEND_STRL("dns_interface"), CURLOPT_DNS_INTERFACE, IS_STRING))) {
    1143             :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1144             :         }
    1145             :         if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip4"), CURLOPT_DNS_LOCAL_IP4, IS_STRING))) {
    1146             :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1147             :         }
    1148             :         if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip6"), CURLOPT_DNS_LOCAL_IP6, IS_STRING))) {
    1149             :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1150             :         }
    1151             : # endif
    1152             : #endif
    1153             : 
    1154             :         /* limits */
    1155         408 :         php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG);
    1156         408 :         php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG);
    1157             : 
    1158             :         /* LSF weirdance
    1159             :         php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG);
    1160             :         php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG);
    1161             :         */
    1162             : 
    1163             :         /* connection handling */
    1164             :         /* crashes
    1165             :         if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) {
    1166             :                 Z_LVAL(opt->defval) = 5;
    1167             :         }
    1168             :         */
    1169         408 :         php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL);
    1170         408 :         php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL);
    1171             : 
    1172             :         /* outgoing interface */
    1173         408 :         php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING);
    1174         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) {
    1175         408 :                 opt->setter = php_http_curle_option_set_portrange;
    1176             :         }
    1177             : 
    1178             :         /* another endpoint port */
    1179         408 :         php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG);
    1180             : 
    1181             :         /* RFC4007 zone_id */
    1182             : #if PHP_HTTP_CURL_VERSION(7,19,0)
    1183         408 :         php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG);
    1184             : #endif
    1185             : 
    1186             :         /* auth */
    1187         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) {
    1188         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1189             :         }
    1190         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG))) {
    1191         408 :                 Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
    1192             :         }
    1193             : 
    1194             :         /* redirects */
    1195         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) {
    1196         408 :                 opt->setter = php_http_curle_option_set_redirect;
    1197             :         }
    1198         408 :         php_http_option_register(registry, ZEND_STRL("unrestricted_auth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL);
    1199             : #if PHP_HTTP_CURL_VERSION(7,19,1)
    1200         408 :         php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_LONG);
    1201             : #endif
    1202             : 
    1203             :         /* retries */
    1204         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) {
    1205         408 :                 opt->setter = php_http_curle_option_set_retrycount;
    1206             :         }
    1207         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) {
    1208         408 :                 opt->setter = php_http_curle_option_set_retrydelay;
    1209             :         }
    1210             : 
    1211             :         /* referer */
    1212         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) {
    1213         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1214             :         }
    1215         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) {
    1216         408 :                 ZVAL_BOOL(&opt->defval, 1);
    1217             :         }
    1218             : 
    1219             :         /* useragent */
    1220         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) {
    1221             :                 /* don't check strlen, to allow sending no useragent at all */
    1222         408 :                 ZVAL_STRING(&opt->defval,
    1223             :                                 "PECL_HTTP/" PHP_PECL_HTTP_VERSION " "
    1224             :                                 "PHP/" PHP_VERSION " "
    1225             :                                 "libcurl/" LIBCURL_VERSION
    1226             :                         , 0);
    1227             :         }
    1228             : 
    1229             :         /* resume */
    1230         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) {
    1231         408 :                 opt->setter = php_http_curle_option_set_resume;
    1232             :         }
    1233             :         /* ranges */
    1234         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) {
    1235         408 :                 opt->setter = php_http_curle_option_set_range;
    1236             :         }
    1237             : 
    1238             :         /* etag */
    1239         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) {
    1240         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1241         408 :                 opt->setter = php_http_curle_option_set_etag;
    1242             :         }
    1243             : 
    1244             :         /* compression */
    1245         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) {
    1246         408 :                 opt->setter = php_http_curle_option_set_compress;
    1247             :         }
    1248             : 
    1249             :         /* lastmodified */
    1250         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) {
    1251         408 :                 opt->setter = php_http_curle_option_set_lastmodified;
    1252             :         }
    1253             : 
    1254             :         /* cookies */
    1255         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) {
    1256         408 :                 opt->setter = php_http_curle_option_set_encodecookies;
    1257         408 :                 ZVAL_BOOL(&opt->defval, 1);
    1258             :         }
    1259         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) {
    1260         408 :                 opt->setter = php_http_curle_option_set_cookies;
    1261             :         }
    1262             : 
    1263             :         /* cookiesession, don't load session cookies from cookiestore */
    1264         408 :         php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL);
    1265             :         /* cookiestore, read initial cookies from that file and store cookies back into that file */
    1266         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) {
    1267         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1268         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1269         408 :                 opt->setter = php_http_curle_option_set_cookiestore;
    1270             :         }
    1271             : 
    1272             :         /* maxfilesize */
    1273         408 :         php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG);
    1274             : 
    1275             :         /* http protocol version */
    1276         408 :         php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG);
    1277             : 
    1278             :         /* timeouts */
    1279         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) {
    1280         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
    1281             :         }
    1282         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) {
    1283         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
    1284         408 :                 Z_DVAL(opt->defval) = 3;
    1285             :         }
    1286             : #if PHP_HTTP_CURL_VERSION(7,36,0)
    1287         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("expect_100_timeout"), CURLOPT_EXPECT_100_TIMEOUT_MS, IS_DOUBLE))) {
    1288         408 :                 opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
    1289         408 :                 Z_DVAL(opt->defval) = 1;
    1290             :         }
    1291             : #endif
    1292             : 
    1293             :         /* tcp */
    1294         408 :         php_http_option_register(registry, ZEND_STRL("tcp_nodelay"), CURLOPT_TCP_NODELAY, IS_BOOL);
    1295             : #if PHP_HTTP_CURL_VERSION(7,25,0)
    1296         408 :         php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL);
    1297         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) {
    1298         408 :                 Z_LVAL(opt->defval) = 60;
    1299             :         }
    1300         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) {
    1301         408 :                 Z_LVAL(opt->defval) = 60;
    1302             :         }
    1303             : #endif
    1304             : 
    1305             :         /* ssl */
    1306         408 :         if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) {
    1307         408 :                 registry = &opt->suboptions;
    1308             : 
    1309         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) {
    1310         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1311         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1312             :                 }
    1313         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) {
    1314         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1315         408 :                         ZVAL_STRING(&opt->defval, "PEM", 0);
    1316             :                 }
    1317         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
    1318         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1319         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1320             :                 }
    1321         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) {
    1322         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1323         408 :                         ZVAL_STRING(&opt->defval, "PEM", 0);
    1324             :                 }
    1325         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) {
    1326         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1327             :                 }
    1328         408 :                 php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
    1329         408 :                 php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
    1330         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) {
    1331         408 :                         ZVAL_BOOL(&opt->defval, 1);
    1332             :                 }
    1333         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) {
    1334         408 :                         ZVAL_BOOL(&opt->defval, 1);
    1335         408 :                         opt->setter = php_http_curle_option_set_ssl_verifyhost;
    1336             :                 }
    1337         408 :                 php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING);
    1338         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) {
    1339         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1340         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1341             : #ifdef PHP_HTTP_CURL_CAINFO
    1342         408 :                         ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0);
    1343             : #endif
    1344             :                 }
    1345         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) {
    1346         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1347         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1348             :                 }
    1349         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) {
    1350         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1351         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1352             :                 }
    1353         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) {
    1354         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1355         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1356             :                 }
    1357             : #if PHP_HTTP_CURL_VERSION(7,19,0)
    1358         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) {
    1359         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1360         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1361             :                 }
    1362             : #       ifdef PHP_HTTP_HAVE_OPENSSL
    1363         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) {
    1364         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
    1365         408 :                         opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
    1366             :                 }
    1367             : #       endif
    1368             : #endif
    1369             : #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
    1370         408 :                 php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL);
    1371             : #endif
    1372             : #if PHP_HTTP_CURL_VERSION(7,36,0)
    1373         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, IS_BOOL))) {
    1374         408 :                         ZVAL_BOOL(&opt->defval, 1);
    1375             :                 }
    1376         408 :                 if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, IS_BOOL))) {
    1377         408 :                         ZVAL_BOOL(&opt->defval, 1);
    1378             :                 }
    1379             : #endif
    1380             :         }
    1381         408 : }
    1382             : 
    1383        2040 : static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *options, void *userdata)
    1384             : {
    1385        2040 :         php_http_client_curl_handler_t *curl = userdata;
    1386             :         zval *option;
    1387             : 
    1388        2040 :         if ((option = php_http_option_get(opt, options, NULL))) {
    1389           3 :                 option = php_http_ztyp(opt->type, option);
    1390           3 :                 zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL);
    1391             :         }
    1392        2040 :         return option;
    1393             : }
    1394             : 
    1395        2040 : static STATUS php_http_curle_set_option(php_http_option_t *opt, zval *val, void *userdata)
    1396             : {
    1397        2040 :         php_http_client_curl_handler_t *curl = userdata;
    1398        2040 :         CURL *ch = curl->handle;
    1399             :         zval tmp;
    1400        2040 :         CURLcode rc = CURLE_OK;
    1401        2040 :         STATUS rv = SUCCESS;
    1402             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
    1403             : 
    1404        2040 :         if (!val) {
    1405           0 :                 val = &opt->defval;
    1406             :         }
    1407             : 
    1408        2040 :         switch (opt->type) {
    1409             :         case IS_BOOL:
    1410         435 :                 if (opt->setter) {
    1411          87 :                         rv = opt->setter(opt, val, curl);
    1412         348 :                 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) {
    1413           0 :                         rv = FAILURE;
    1414             :                 }
    1415         435 :                 break;
    1416             : 
    1417             :         case IS_LONG:
    1418         818 :                 if (opt->setter) {
    1419         172 :                         rv = opt->setter(opt, val, curl);
    1420         646 :                 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) {
    1421           0 :                         rv = FAILURE;
    1422             :                 }
    1423         818 :                 break;
    1424             : 
    1425             :         case IS_STRING:
    1426         400 :                 if (opt->setter) {
    1427          86 :                         rv = opt->setter(opt, val, curl);
    1428         314 :                 } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) && !Z_STRLEN_P(val)) {
    1429         360 :                         if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
    1430           0 :                                 rv = FAILURE;
    1431             :                         }
    1432         134 :                 } else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) && Z_STRVAL_P(val) && SUCCESS != php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) {
    1433           0 :                         if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
    1434           0 :                                 rv = FAILURE;
    1435             :                         }
    1436         134 :                 } else if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val)))) {
    1437           0 :                         rv = FAILURE;
    1438             :                 }
    1439         400 :                 break;
    1440             : 
    1441             :         case IS_DOUBLE:
    1442         172 :                 if (opt->flags & PHP_HTTP_CURLE_OPTION_TRANSFORM_MS) {
    1443         129 :                         tmp = *val;
    1444         129 :                         Z_DVAL(tmp) *= 1000;
    1445         129 :                         val = &tmp;
    1446             :                 }
    1447         172 :                 if (opt->setter) {
    1448          43 :                         rv = opt->setter(opt, val, curl);
    1449         129 :                 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) {
    1450           0 :                         rv = FAILURE;
    1451             :                 }
    1452         172 :                 break;
    1453             : 
    1454             :         case IS_ARRAY:
    1455         215 :                 if (opt->setter) {
    1456         172 :                         rv = opt->setter(opt, val, curl);
    1457          43 :                 } else if (Z_TYPE_P(val) != IS_NULL) {
    1458           1 :                         rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), curl);
    1459             :                 }
    1460         215 :                 break;
    1461             : 
    1462             :         default:
    1463           0 :                 if (opt->setter) {
    1464           0 :                         rv = opt->setter(opt, val, curl);
    1465             :                 } else {
    1466           0 :                         rv = FAILURE;
    1467             :                 }
    1468           0 :                 break;
    1469             :         }
    1470        2040 :         if (rv != SUCCESS) {
    1471           0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_easy_strerror(rc));
    1472             :         }
    1473        2040 :         return rv;
    1474             : }
    1475             : 
    1476             : 
    1477             : /* client ops */
    1478             : 
    1479          43 : static STATUS php_http_client_curl_handler_reset(php_http_client_curl_handler_t *curl)
    1480             : {
    1481          43 :         CURL *ch = curl->handle;
    1482             :         php_http_curle_storage_t *st;
    1483             : 
    1484          43 :         if ((st = php_http_curle_get_storage(ch))) {
    1485          43 :                 if (st->url) {
    1486           6 :                         pefree(st->url, 1);
    1487           6 :                         st->url = NULL;
    1488             :                 }
    1489          43 :                 if (st->cookiestore) {
    1490           0 :                         pefree(st->cookiestore, 1);
    1491           0 :                         st->cookiestore = NULL;
    1492             :                 }
    1493          43 :                 st->errorbuffer[0] = '\0';
    1494             :         }
    1495             : 
    1496          43 :         curl_easy_setopt(ch, CURLOPT_URL, NULL);
    1497          43 :         curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, NULL);
    1498          43 :         curl_easy_setopt(ch, CURLOPT_HTTPGET, 1L);
    1499          43 :         curl_easy_setopt(ch, CURLOPT_NOBODY, 0L);
    1500             :         /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
    1501             : #if PHP_HTTP_CURL_VERSION(7,19,1)
    1502          43 :         curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL);
    1503          43 :         curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL);
    1504          43 :         curl_easy_setopt(ch, CURLOPT_USERNAME, NULL);
    1505          43 :         curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL);
    1506             : #endif
    1507             : 
    1508             : #if PHP_HTTP_CURL_VERSION(7,21,3)
    1509          43 :         if (curl->options.resolve) {
    1510           0 :                 curl_slist_free_all(curl->options.resolve);
    1511           0 :                 curl->options.resolve = NULL;
    1512             :         }
    1513             : #endif
    1514          43 :         curl->options.retry.count = 0;
    1515          43 :         curl->options.retry.delay = 0;
    1516          43 :         curl->options.redirects = 0;
    1517          43 :         curl->options.encode_cookies = 1;
    1518             : 
    1519          43 :         if (curl->options.headers) {
    1520           0 :                 curl_slist_free_all(curl->options.headers);
    1521           0 :                 curl->options.headers = NULL;
    1522             :         }
    1523             : 
    1524          43 :         php_http_buffer_reset(&curl->options.cookies);
    1525          43 :         php_http_buffer_reset(&curl->options.ranges);
    1526             : 
    1527          43 :         return SUCCESS;
    1528             : }
    1529             : 
    1530          43 : static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf)
    1531             : {
    1532             :         void *handle;
    1533             :         php_http_client_curl_handler_t *handler;
    1534             :         TSRMLS_FETCH_FROM_CTX(h->ts);
    1535             : 
    1536          43 :         if (!(handle = php_resource_factory_handle_ctor(rf, NULL TSRMLS_CC))) {
    1537           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle");
    1538           0 :                 return NULL;
    1539             :         }
    1540             : 
    1541          43 :         handler = ecalloc(1, sizeof(*handler));
    1542          43 :         handler->rf = rf;
    1543          43 :         handler->client = h;
    1544          43 :         handler->handle = handle;
    1545          43 :         handler->request.buffer = php_http_buffer_init(NULL);
    1546          43 :         handler->request.parser = php_http_message_parser_init(NULL TSRMLS_CC);
    1547          43 :         handler->request.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC);
    1548          43 :         handler->response.buffer = php_http_buffer_init(NULL);
    1549          43 :         handler->response.parser = php_http_message_parser_init(NULL TSRMLS_CC);
    1550          43 :         handler->response.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC);
    1551          43 :         php_http_buffer_init(&handler->options.cookies);
    1552          43 :         php_http_buffer_init(&handler->options.ranges);
    1553          43 :         zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0);
    1554             : 
    1555             : #if defined(ZTS)
    1556             :         curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
    1557             : #endif
    1558          43 :         curl_easy_setopt(handle, CURLOPT_HEADER, 0L);
    1559          43 :         curl_easy_setopt(handle, CURLOPT_FILETIME, 1L);
    1560          43 :         curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L);
    1561          43 :         curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
    1562          43 :         curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
    1563          43 :         curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL);
    1564          43 :         curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curle_dummy_callback);
    1565          43 :         curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback);
    1566          43 :         curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curle_read_callback);
    1567          43 :         curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curle_ioctl_callback);
    1568             : #if PHP_HTTP_CURL_VERSION(7,32,0)
    1569          43 :         curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback);
    1570          43 :         curl_easy_setopt(handle, CURLOPT_XFERINFODATA, handler);
    1571             : #else
    1572             :         curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback);
    1573             :         curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler);
    1574             : #endif
    1575          43 :         curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler);
    1576             : 
    1577          43 :         php_http_client_curl_handler_reset(handler);
    1578             : 
    1579          43 :         return handler;
    1580             : }
    1581             : 
    1582             : 
    1583          43 : static STATUS php_http_client_curl_handler_prepare(php_http_client_curl_handler_t *curl, php_http_client_enqueue_t *enqueue)
    1584             : {
    1585             :         size_t body_size;
    1586          43 :         php_http_message_t *msg = enqueue->request;
    1587          43 :         php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle);
    1588             :         TSRMLS_FETCH_FROM_CTX(curl->client->ts);
    1589             : 
    1590             :         /* request url */
    1591          43 :         if (!PHP_HTTP_INFO(msg).request.url) {
    1592           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL");
    1593           0 :                 return FAILURE;
    1594             :         }
    1595          43 :         storage->errorbuffer[0] = '\0';
    1596          43 :         if (storage->url) {
    1597           0 :                 pefree(storage->url, 1);
    1598             :         }
    1599          43 :         storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 1);
    1600          43 :         curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url);
    1601             : 
    1602             :         /* request method */
    1603          43 :         switch (php_http_select_str(PHP_HTTP_INFO(msg).request.method, 4, "GET", "HEAD", "POST", "PUT")) {
    1604             :                 case 0:
    1605          37 :                         curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1L);
    1606          37 :                         break;
    1607             : 
    1608             :                 case 1:
    1609           0 :                         curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L);
    1610           0 :                         break;
    1611             : 
    1612             :                 case 2:
    1613           4 :                         curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
    1614           4 :                         break;
    1615             : 
    1616             :                 case 3:
    1617           2 :                         curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
    1618           2 :                         break;
    1619             : 
    1620             :                 default: {
    1621           0 :                         if (PHP_HTTP_INFO(msg).request.method) {
    1622           0 :                                 curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method);
    1623             :                         } else {
    1624           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot use empty request method");
    1625           0 :                                 return FAILURE;
    1626             :                         }
    1627           0 :                         break;
    1628             :                 }
    1629             :         }
    1630             : 
    1631             :         /* request headers */
    1632          43 :         php_http_message_update_headers(msg);
    1633          43 :         if (zend_hash_num_elements(&msg->hdrs)) {
    1634           5 :                 php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0);
    1635             :                 zval **header_val;
    1636             :                 HashPosition pos;
    1637             :                 php_http_buffer_t header;
    1638             : 
    1639           5 :                 php_http_buffer_init(&header);
    1640          11 :                 FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) {
    1641           6 :                         if (header_key.type == HASH_KEY_IS_STRING) {
    1642           6 :                                 zval *header_cpy = php_http_ztyp(IS_STRING, *header_val);
    1643             : 
    1644           6 :                                 php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy));
    1645           6 :                                 php_http_buffer_fix(&header);
    1646           6 :                                 curl->options.headers = curl_slist_append(curl->options.headers, header.data);
    1647           6 :                                 php_http_buffer_reset(&header);
    1648             : 
    1649           6 :                                 zval_ptr_dtor(&header_cpy);
    1650             :                         }
    1651             :                 }
    1652           5 :                 php_http_buffer_dtor(&header);
    1653             :         }
    1654          43 :         curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers);
    1655             : 
    1656             :         /* attach request body */
    1657          43 :         if ((body_size = php_http_message_body_size(msg->body))) {
    1658             :                 /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the
    1659             :                  * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.«
    1660             :                  * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the
    1661             :                  * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method
    1662             :                  * does not allow a request body.
    1663             :                  */
    1664           4 :                 php_stream_rewind(php_http_message_body_stream(msg->body));
    1665           4 :                 curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, msg->body);
    1666           4 :                 curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body);
    1667           4 :                 curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size);
    1668           4 :                 curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size);
    1669             :         } else {
    1670          39 :                 curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, NULL);
    1671          39 :                 curl_easy_setopt(curl->handle, CURLOPT_READDATA, NULL);
    1672          39 :                 curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, 0L);
    1673          39 :                 curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, 0L);
    1674             :         }
    1675             : 
    1676          43 :         php_http_options_apply(&php_http_curle_options, enqueue->options, curl);
    1677             : 
    1678          43 :         return SUCCESS;
    1679             : }
    1680             : 
    1681          86 : static void php_http_client_curl_handler_clear(php_http_client_curl_handler_t *handler)
    1682             : {
    1683          86 :         curl_easy_setopt(handler->handle, CURLOPT_NOPROGRESS, 1L);
    1684             : #if PHP_HTTP_CURL_VERSION(7,32,0)
    1685          86 :         curl_easy_setopt(handler->handle, CURLOPT_XFERINFOFUNCTION, NULL);
    1686             : #else
    1687             :         curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL);
    1688             : #endif
    1689          86 :         curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L);
    1690          86 :         curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL);
    1691          86 : }
    1692             : 
    1693          43 : static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler)
    1694             : {
    1695             :         TSRMLS_FETCH_FROM_CTX(handler->client->ts);
    1696             : 
    1697          43 :         php_http_client_curl_handler_clear(handler);
    1698             : 
    1699          43 :         php_resource_factory_handle_dtor(handler->rf, handler->handle TSRMLS_CC);
    1700          43 :         php_resource_factory_free(&handler->rf);
    1701             : 
    1702          43 :         php_http_message_parser_free(&handler->request.parser);
    1703          43 :         php_http_message_free(&handler->request.message);
    1704          43 :         php_http_buffer_free(&handler->request.buffer);
    1705          43 :         php_http_message_parser_free(&handler->response.parser);
    1706          43 :         php_http_message_free(&handler->response.message);
    1707          43 :         php_http_buffer_free(&handler->response.buffer);
    1708          43 :         php_http_buffer_dtor(&handler->options.ranges);
    1709          43 :         php_http_buffer_dtor(&handler->options.cookies);
    1710          43 :         zend_hash_destroy(&handler->options.cache);
    1711             : 
    1712          43 :         if (handler->options.headers) {
    1713           5 :                 curl_slist_free_all(handler->options.headers);
    1714           5 :                 handler->options.headers = NULL;
    1715             :         }
    1716             : 
    1717          43 :         efree(handler);
    1718          43 : }
    1719             : 
    1720          29 : static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void *handle)
    1721             : {
    1722             :         php_http_client_curl_t *curl;
    1723             :         TSRMLS_FETCH_FROM_CTX(h->ts);
    1724             : 
    1725          29 :         if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) {
    1726           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle");
    1727           0 :                 return NULL;
    1728             :         }
    1729             : 
    1730          29 :         curl = ecalloc(1, sizeof(*curl));
    1731          29 :         curl->handle = handle;
    1732          29 :         curl->unfinished = 0;
    1733          29 :         h->ctx = curl;
    1734             : 
    1735          29 :         return h;
    1736             : }
    1737             : 
    1738          29 : static void php_http_client_curl_dtor(php_http_client_t *h)
    1739             : {
    1740          29 :         php_http_client_curl_t *curl = h->ctx;
    1741             :         TSRMLS_FETCH_FROM_CTX(h->ts);
    1742             : 
    1743             : #if PHP_HTTP_HAVE_EVENT
    1744          29 :         if (curl->timeout) {
    1745           6 :                 if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
    1746           1 :                         event_del(curl->timeout);
    1747             :                 }
    1748           6 :                 efree(curl->timeout);
    1749           6 :                 curl->timeout = NULL;
    1750             :         }
    1751          29 :         if (curl->evbase) {
    1752           6 :                 event_base_free(curl->evbase);
    1753           6 :                 curl->evbase = NULL;
    1754             :         }
    1755             : #endif
    1756          29 :         curl->unfinished = 0;
    1757             : 
    1758          29 :         php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC);
    1759             : 
    1760          29 :         efree(curl);
    1761          29 :         h->ctx = NULL;
    1762          29 : }
    1763             : 
    1764          43 : static void queue_dtor(php_http_client_enqueue_t *e)
    1765             : {
    1766          43 :         php_http_client_curl_handler_t *handler = e->opaque;
    1767             : 
    1768          43 :         if (handler->queue.dtor) {
    1769          43 :                 e->opaque = handler->queue.opaque;
    1770          43 :                 handler->queue.dtor(e);
    1771             :         }
    1772          43 :         php_http_client_curl_handler_dtor(handler);
    1773          43 : }
    1774             : 
    1775          43 : static php_resource_factory_t *create_rf(const char *url TSRMLS_DC)
    1776             : {
    1777             :         php_url *purl;
    1778          43 :         php_resource_factory_t *rf = NULL;
    1779             : 
    1780          43 :         if (!url || !*url) {
    1781           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL");
    1782           0 :                 return NULL;
    1783             :         }
    1784             : 
    1785          43 :         purl = php_url_parse(url);
    1786             : 
    1787          43 :         if (!purl) {
    1788           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse URL '%s'", url);
    1789           0 :                 return NULL;
    1790             :         } else {
    1791          43 :                 char *id_str = NULL;
    1792          43 :                 size_t id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(purl->host), purl->port ? purl->port : 80);
    1793          43 :                 php_persistent_handle_factory_t *pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC);
    1794             : 
    1795          43 :                 if (pf) {
    1796          43 :                         rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void*)) php_persistent_handle_abandon);
    1797             :                 }
    1798             : 
    1799          43 :                 php_url_free(purl);
    1800          43 :                 efree(id_str);
    1801             :         }
    1802             : 
    1803          43 :         if (!rf) {
    1804           0 :                 rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL);
    1805             :         }
    1806             : 
    1807          43 :         return rf;
    1808             : }
    1809             : 
    1810          43 : static STATUS php_http_client_curl_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
    1811             : {
    1812             :         CURLMcode rs;
    1813          43 :         php_http_client_curl_t *curl = h->ctx;
    1814             :         php_http_client_curl_handler_t *handler;
    1815             :         php_http_client_progress_state_t *progress;
    1816             :         php_resource_factory_t *rf;
    1817             :         TSRMLS_FETCH_FROM_CTX(h->ts);
    1818             : 
    1819          43 :         rf = create_rf(enqueue->request->http.info.request.url TSRMLS_CC);
    1820          43 :         if (!rf) {
    1821           0 :                 return FAILURE;
    1822             :         }
    1823             : 
    1824          43 :         handler = php_http_client_curl_handler_init(h, rf);
    1825          43 :         if (!handler) {
    1826           0 :                 return FAILURE;
    1827             :         }
    1828             : 
    1829          43 :         if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) {
    1830           0 :                 php_http_client_curl_handler_dtor(handler);
    1831           0 :                 return FAILURE;
    1832             :         }
    1833             : 
    1834          43 :         handler->queue = *enqueue;
    1835          43 :         enqueue->opaque = handler;
    1836          43 :         enqueue->dtor = queue_dtor;
    1837             : 
    1838          43 :         if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, handler->handle))) {
    1839          43 :                 zend_llist_add_element(&h->requests, enqueue);
    1840          43 :                 ++curl->unfinished;
    1841             : 
    1842          43 :                 if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) {
    1843          43 :                         progress->info = "start";
    1844          43 :                         h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress);
    1845          43 :                         progress->started = 1;
    1846             :                 }
    1847             : 
    1848          43 :                 return SUCCESS;
    1849             :         } else {
    1850           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs));
    1851           0 :                 return FAILURE;
    1852             :         }
    1853             : }
    1854             : 
    1855          43 : static STATUS php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
    1856             : {
    1857             :         CURLMcode rs;
    1858          43 :         php_http_client_curl_t *curl = h->ctx;
    1859          43 :         php_http_client_curl_handler_t *handler = enqueue->opaque;
    1860             :         TSRMLS_FETCH_FROM_CTX(h->ts);
    1861             : 
    1862          43 :         php_http_client_curl_handler_clear(handler);
    1863          43 :         if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, handler->handle))) {
    1864          43 :                 zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue);
    1865          43 :                 return SUCCESS;
    1866             :         } else {
    1867           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs));
    1868             :         }
    1869             : 
    1870           0 :         return FAILURE;
    1871             : }
    1872             : 
    1873          30 : static void php_http_client_curl_reset(php_http_client_t *h)
    1874             : {
    1875             :         zend_llist_element *next_el, *this_el;
    1876             : 
    1877          67 :         for (this_el = h->requests.head; this_el; this_el = next_el) {
    1878          37 :                 next_el = this_el->next;
    1879          37 :                 php_http_client_curl_dequeue(h, (void *) this_el->data);
    1880             :         }
    1881          30 : }
    1882             : 
    1883        1929 : static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout)
    1884             : {
    1885        1929 :         if ((CURLM_OK == curl_multi_timeout(curl->handle, &max_tout)) && (max_tout > 0)) {
    1886        1927 :                 timeout->tv_sec = max_tout / 1000;
    1887        1927 :                 timeout->tv_usec = (max_tout % 1000) * 1000;
    1888             :         } else {
    1889           2 :                 timeout->tv_sec = 0;
    1890           2 :                 timeout->tv_usec = 1000;
    1891             :         }
    1892        1929 : }
    1893             : 
    1894             : #ifdef PHP_WIN32
    1895             : #       define SELECT_ERROR SOCKET_ERROR
    1896             : #else
    1897             : #       define SELECT_ERROR -1
    1898             : #endif
    1899             : 
    1900        1966 : static STATUS php_http_client_curl_wait(php_http_client_t *h, struct timeval *custom_timeout)
    1901             : {
    1902             :         int MAX;
    1903             :         fd_set R, W, E;
    1904             :         struct timeval timeout;
    1905        1966 :         php_http_client_curl_t *curl = h->ctx;
    1906             : 
    1907             : #if PHP_HTTP_HAVE_EVENT
    1908        1966 :         if (curl->useevents) {
    1909           6 :                 if (!event_initialized(curl->timeout)) {
    1910           0 :                         event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, h);
    1911           6 :                 } else if (custom_timeout && timerisset(custom_timeout)) {
    1912           6 :                         event_add(curl->timeout, custom_timeout);
    1913           0 :                 } else if (!event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
    1914           0 :                         php_http_client_curl_get_timeout(curl, 1000, &timeout);
    1915           0 :                         event_add(curl->timeout, &timeout);
    1916             :                 }
    1917             : 
    1918           6 :                 event_base_loop(curl->evbase, EVLOOP_ONCE);
    1919             : 
    1920           6 :                 return SUCCESS;
    1921             :         }
    1922             : #endif
    1923             : 
    1924        1960 :         FD_ZERO(&R);
    1925        1960 :         FD_ZERO(&W);
    1926        1960 :         FD_ZERO(&E);
    1927             : 
    1928        1960 :         if (CURLM_OK == curl_multi_fdset(curl->handle, &R, &W, &E, &MAX)) {
    1929        1960 :                 if (custom_timeout && timerisset(custom_timeout)) {
    1930          31 :                         timeout = *custom_timeout;
    1931             :                 } else {
    1932        1929 :                         php_http_client_curl_get_timeout(curl, 1000, &timeout);
    1933             :                 }
    1934             : 
    1935        1960 :                 if (MAX == -1) {
    1936        1852 :                         php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC));
    1937        1852 :                         return SUCCESS;
    1938         108 :                 } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) {
    1939         108 :                         return SUCCESS;
    1940             :                 }
    1941             :         }
    1942           0 :         return FAILURE;
    1943             : }
    1944             : 
    1945        1986 : static int php_http_client_curl_once(php_http_client_t *h)
    1946             : {
    1947        1986 :         php_http_client_curl_t *curl = h->ctx;
    1948             : 
    1949             : #if PHP_HTTP_HAVE_EVENT
    1950        1986 :         if (curl->useevents) {
    1951           7 :                 event_base_loop(curl->evbase, EVLOOP_NONBLOCK);
    1952             :         } else
    1953             : #endif
    1954        1979 :         while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle, &curl->unfinished));
    1955             : 
    1956        1986 :         php_http_curlm_responsehandler(h);
    1957             : 
    1958        1986 :         return curl->unfinished;
    1959             : 
    1960             : }
    1961             : 
    1962          20 : static STATUS php_http_client_curl_exec(php_http_client_t *h)
    1963             : {
    1964             : #if PHP_HTTP_HAVE_EVENT
    1965          20 :         php_http_client_curl_t *curl = h->ctx;
    1966             : #endif
    1967             :         TSRMLS_FETCH_FROM_CTX(h->ts);
    1968             : 
    1969             : #if PHP_HTTP_HAVE_EVENT
    1970          20 :         if (curl->useevents) {
    1971           2 :                 php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
    1972             :                 do {
    1973           2 :                         int ev_rc = event_base_dispatch(curl->evbase);
    1974             : 
    1975             : #if DBG_EVENTS
    1976             :                         fprintf(stderr, "%c", "X.0"[ev_rc+1]);
    1977             : #endif
    1978             : 
    1979           2 :                         if (ev_rc < 0) {
    1980           0 :                                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error in event_base_dispatch()");
    1981           0 :                                 return FAILURE;
    1982             :                         }
    1983           2 :                 } while (curl->unfinished);
    1984             :         } else
    1985             : #endif
    1986             :         {
    1987        1965 :                 while (php_http_client_curl_once(h)) {
    1988        1929 :                         if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
    1989             : #ifdef PHP_WIN32
    1990             :                                 /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
    1991             :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
    1992             : #else
    1993           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
    1994             : #endif
    1995           0 :                                 return FAILURE;
    1996             :                         }
    1997             :                 }
    1998             :         }
    1999             : 
    2000          20 :         return SUCCESS;
    2001             : }
    2002             : 
    2003           7 : static STATUS php_http_client_curl_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
    2004             : {
    2005           7 :         php_http_client_curl_t *curl = h->ctx;
    2006             : 
    2007           7 :         switch (opt) {
    2008             :                 case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING:
    2009           1 :                         if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) {
    2010           0 :                                 return FAILURE;
    2011             :                         }
    2012           1 :                         break;
    2013             : 
    2014             :                 case PHP_HTTP_CLIENT_OPT_USE_EVENTS:
    2015             : #if PHP_HTTP_HAVE_EVENT
    2016           6 :                         if ((curl->useevents = *((zend_bool *) arg))) {
    2017           6 :                                 if (!curl->evbase) {
    2018           6 :                                         curl->evbase = event_base_new();
    2019             :                                 }
    2020           6 :                                 if (!curl->timeout) {
    2021           6 :                                         curl->timeout = ecalloc(1, sizeof(struct event));
    2022             :                                 }
    2023           6 :                                 curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, h);
    2024           6 :                                 curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback);
    2025           6 :                                 curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h);
    2026           6 :                                 curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback);
    2027             :                         } else {
    2028           0 :                                 curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, NULL);
    2029           0 :                                 curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, NULL);
    2030           0 :                                 curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, NULL);
    2031           0 :                                 curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, NULL);
    2032             :                         }
    2033           6 :                         break;
    2034             : #endif
    2035             : 
    2036             :                 default:
    2037           0 :                         return FAILURE;
    2038             :         }
    2039           7 :         return SUCCESS;
    2040             : }
    2041             : 
    2042         124 : static STATUS php_http_client_curl_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void **res)
    2043             : {
    2044             :         php_http_client_enqueue_t *enqueue;
    2045             : 
    2046         124 :         switch (opt) {
    2047             :         case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO:
    2048          99 :                 if ((enqueue = php_http_client_enqueued(h, arg, NULL))) {
    2049          99 :                         php_http_client_curl_handler_t *handler = enqueue->opaque;
    2050             : 
    2051          99 :                         *((php_http_client_progress_state_t **) res) = &handler->progress;
    2052          99 :                         return SUCCESS;
    2053             :                 }
    2054           0 :                 break;
    2055             : 
    2056             :         case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO:
    2057          25 :                 if ((enqueue = php_http_client_enqueued(h, arg, NULL))) {
    2058          25 :                         php_http_client_curl_handler_t *handler = enqueue->opaque;
    2059             : 
    2060          25 :                         php_http_curle_get_info(handler->handle, *(HashTable **) res);
    2061          25 :                         return SUCCESS;
    2062             :                 }
    2063           0 :                 break;
    2064             : 
    2065             :         default:
    2066           0 :                 break;
    2067             :         }
    2068             : 
    2069           0 :         return FAILURE;
    2070             : }
    2071             : 
    2072             : static php_http_client_ops_t php_http_client_curl_ops = {
    2073             :         &php_http_curlm_resource_factory_ops,
    2074             :         php_http_client_curl_init,
    2075             :         NULL /* copy */,
    2076             :         php_http_client_curl_dtor,
    2077             :         php_http_client_curl_reset,
    2078             :         php_http_client_curl_exec,
    2079             :         php_http_client_curl_wait,
    2080             :         php_http_client_curl_once,
    2081             :         php_http_client_curl_enqueue,
    2082             :         php_http_client_curl_dequeue,
    2083             :         php_http_client_curl_setopt,
    2084             :         php_http_client_curl_getopt
    2085             : };
    2086             : 
    2087           0 : php_http_client_ops_t *php_http_client_curl_get_ops(void)
    2088             : {
    2089           0 :         return &php_http_client_curl_ops;
    2090             : }
    2091             : 
    2092         408 : PHP_MINIT_FUNCTION(http_client_curl)
    2093             : {
    2094             :         php_http_options_t *options;
    2095         408 :         php_http_client_driver_t driver = {
    2096             :                 ZEND_STRL("curl"),
    2097             :                 &php_http_client_curl_ops
    2098             :         };
    2099             : 
    2100         408 :         if (SUCCESS != php_http_client_driver_add(&driver)) {
    2101           0 :                         return FAILURE;
    2102             :                 }
    2103             : 
    2104         408 :         if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl"), &php_http_curlm_resource_factory_ops, NULL, NULL TSRMLS_CC)) {
    2105           0 :                 return FAILURE;
    2106             :         }
    2107         408 :         if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl\\Request"), &php_http_curle_resource_factory_ops, NULL, NULL TSRMLS_CC)) {
    2108           0 :                 return FAILURE;
    2109             :         }
    2110             : 
    2111         408 :         if ((options = php_http_options_init(&php_http_curle_options, 1))) {
    2112         408 :                 options->getter = php_http_curle_get_option;
    2113         408 :                 options->setter = php_http_curle_set_option;
    2114             : 
    2115         408 :                 php_http_curle_options_init(options TSRMLS_CC);
    2116             :         }
    2117             : 
    2118             :         /*
    2119             :         * HTTP Protocol Version Constants
    2120             :         */
    2121         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0, CONST_CS|CONST_PERSISTENT);
    2122         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1, CONST_CS|CONST_PERSISTENT);
    2123         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT);
    2124             : 
    2125             :         /*
    2126             :         * SSL Version Constants
    2127             :         */
    2128         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1, CONST_CS|CONST_PERSISTENT);
    2129             : #if PHP_HTTP_CURL_VERSION(7,34,0)
    2130         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_0", CURL_SSLVERSION_TLSv1_0, CONST_CS|CONST_PERSISTENT);
    2131         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_1", CURL_SSLVERSION_TLSv1_1, CONST_CS|CONST_PERSISTENT);
    2132         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_2", CURL_SSLVERSION_TLSv1_2, CONST_CS|CONST_PERSISTENT);
    2133             : #endif
    2134         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2, CONST_CS|CONST_PERSISTENT);
    2135         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3, CONST_CS|CONST_PERSISTENT);
    2136         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT, CONST_CS|CONST_PERSISTENT);
    2137             : 
    2138             :         /*
    2139             :         * DNS IPvX resolving
    2140             :         */
    2141         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V4", CURL_IPRESOLVE_V4, CONST_CS|CONST_PERSISTENT);
    2142         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V6", CURL_IPRESOLVE_V6, CONST_CS|CONST_PERSISTENT);
    2143         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER, CONST_CS|CONST_PERSISTENT);
    2144             : 
    2145             :         /*
    2146             :         * Auth Constants
    2147             :         */
    2148         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BASIC", CURLAUTH_BASIC, CONST_CS|CONST_PERSISTENT);
    2149         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS|CONST_PERSISTENT);
    2150             : #if PHP_HTTP_CURL_VERSION(7,19,3)
    2151         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE, CONST_CS|CONST_PERSISTENT);
    2152             : #endif
    2153         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NTLM", CURLAUTH_NTLM, CONST_CS|CONST_PERSISTENT);
    2154         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT);
    2155             : #if PHP_HTTP_CURL_VERSION(7,38,0)
    2156         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_SPNEGO", CURLAUTH_NEGOTIATE, CONST_CS|CONST_PERSISTENT);
    2157             : #endif
    2158         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_ANY", CURLAUTH_ANY, CONST_CS|CONST_PERSISTENT);
    2159             : 
    2160             :         /*
    2161             :         * Proxy Type Constants
    2162             :         */
    2163         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4", CURLPROXY_SOCKS4, CONST_CS|CONST_PERSISTENT);
    2164         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4A", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT);
    2165         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT);
    2166         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT);
    2167         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP", CURLPROXY_HTTP, CONST_CS|CONST_PERSISTENT);
    2168             : #if PHP_HTTP_CURL_VERSION(7,19,4)
    2169         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0, CONST_CS|CONST_PERSISTENT);
    2170             : #endif
    2171             : 
    2172             :         /*
    2173             :         * Post Redirection Constants
    2174             :         */
    2175             : #if PHP_HTTP_CURL_VERSION(7,19,1)
    2176         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_301", CURL_REDIR_POST_301, CONST_CS|CONST_PERSISTENT);
    2177         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_302", CURL_REDIR_POST_302, CONST_CS|CONST_PERSISTENT);
    2178             : #if PHP_HTTP_CURL_VERSION(7,26,0)
    2179         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_303", CURL_REDIR_POST_303, CONST_CS|CONST_PERSISTENT);
    2180             : #endif
    2181         408 :         REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_ALL", CURL_REDIR_POST_ALL, CONST_CS|CONST_PERSISTENT);
    2182             : #endif
    2183             : 
    2184         408 :         return SUCCESS;
    2185             : }
    2186             : 
    2187         408 : PHP_MSHUTDOWN_FUNCTION(http_client_curl)
    2188             : {
    2189         408 :         php_persistent_handle_cleanup(ZEND_STRL("http\\Client\\Curl"), NULL, 0 TSRMLS_CC);
    2190         408 :         php_persistent_handle_cleanup(ZEND_STRL("http\\Client\\Curl\\Request"), NULL, 0 TSRMLS_CC);
    2191             : 
    2192         408 :         php_http_options_dtor(&php_http_curle_options);
    2193             : 
    2194         408 :         return SUCCESS;
    2195             : }
    2196             : 
    2197             : #endif /* PHP_HTTP_HAVE_CURL */
    2198             : 
    2199             : /*
    2200             :  * Local variables:
    2201             :  * tab-width: 4
    2202             :  * c-basic-offset: 4
    2203             :  * End:
    2204             :  * vim600: noet sw=4 ts=4 fdm=marker
    2205             :  * vim<600: noet sw=4 ts=4
    2206             :  */

Generated by: LCOV version 1.11