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

Generated by: LCOV version 1.11