#include "php_http_api.h"
#include "php_http_client.h"
+#include "php_http_client_curl_event.h"
+#include "php_http_client_curl_user.h"
#if PHP_HTTP_HAVE_CURL
-#if PHP_HTTP_HAVE_EVENT
-# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
-# include <event.h>
-# define event_base_new event_init
-# define event_assign(e, b, s, a, cb, d) do {\
- event_set(e, s, a, cb, d); \
- event_base_set(b, e); \
- } while(0)
-# else
-# if PHP_HTTP_HAVE_EVENT2
-# include <event2/event.h>
-# include <event2/event_struct.h>
-# else
-# error "libevent presence is unknown"
-# endif
-# endif
-# ifndef DBG_EVENTS
-# define DBG_EVENTS 0
-# endif
-#endif
-
#ifdef PHP_HTTP_HAVE_OPENSSL
# include <openssl/ssl.h>
#endif
# include <gnutls.h>
#endif
-typedef struct php_http_client_curl_handle {
- CURLM *multi;
- CURLSH *share;
-} php_http_client_curl_handle_t;
-
-typedef struct php_http_client_curl {
- php_http_client_curl_handle_t *handle;
-
- int unfinished; /* int because of curl_multi_perform() */
-
-#if PHP_HTTP_HAVE_EVENT
- struct event_base *evbase;
- struct event *timeout;
- unsigned useevents:1;
-#endif
-} php_http_client_curl_t;
-
typedef struct php_http_client_curl_handler {
CURL *handle;
php_resource_factory_t *rf;
#endif
{
php_http_client_curl_handler_t *h = ctx;
- zend_bool update = 0;
if (h->progress.dl.total != dltotal
|| h->progress.dl.now != dlnow
|| h->progress.ul.total != ultotal
|| h->progress.ul.now != ulnow
) {
- update = 1;
-
h->progress.dl.total = dltotal;
h->progress.dl.now = dlnow;
h->progress.ul.total = ultotal;
h->progress.ul.now = ulnow;
}
- if (update && h->client->callback.progress.func) {
+ if (h->client->callback.progress.func) {
h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
}
static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
{
php_http_client_curl_handler_t *h = ctx;
+ unsigned utype = PHP_HTTP_CLIENT_DEBUG_INFO;
/* catch progress */
switch (type) {
h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
}
break;
+
case CURLINFO_HEADER_OUT:
- case CURLINFO_DATA_OUT:
+ utype |= PHP_HTTP_CLIENT_DEBUG_HEADER;
+ goto data_out;
+
case CURLINFO_SSL_DATA_OUT:
+ utype |= PHP_HTTP_CLIENT_DEBUG_SSL;
+ goto data_out;
+
+ case CURLINFO_DATA_OUT:
+ data_out:
+ utype |= PHP_HTTP_CLIENT_DEBUG_OUT;
h->progress.info = "send";
break;
+
case CURLINFO_HEADER_IN:
- case CURLINFO_DATA_IN:
+ utype |= PHP_HTTP_CLIENT_DEBUG_HEADER;
+ goto data_in;
+
case CURLINFO_SSL_DATA_IN:
+ utype |= PHP_HTTP_CLIENT_DEBUG_SSL;
+ goto data_in;
+
+ case CURLINFO_DATA_IN:
+ data_in:
+ utype |= PHP_HTTP_CLIENT_DEBUG_IN;
h->progress.info = "receive";
break;
+
default:
break;
}
+ if (h->client->callback.debug.func) {
+ h->client->callback.debug.func(h->client->callback.debug.arg, h->client, &h->queue, utype, data, length);
+ }
+
#if 0
/* debug */
_dpf(type, data, length);
return response;
}
-static void php_http_curlm_responsehandler(php_http_client_t *context)
+void php_http_client_curl_responsehandler(php_http_client_t *context)
{
int err_count = 0, remaining = 0;
php_http_curle_storage_t *st, *err = NULL;
}
}
-#if PHP_HTTP_HAVE_EVENT
-
-typedef struct php_http_curlm_event {
- struct event evnt;
- php_http_client_t *context;
-} php_http_curlm_event_t;
-
-static inline int etoca(short action) {
- switch (action & (EV_READ|EV_WRITE)) {
- case EV_READ:
- return CURL_CSELECT_IN;
- break;
- case EV_WRITE:
- return CURL_CSELECT_OUT;
- break;
- case EV_READ|EV_WRITE:
- return CURL_CSELECT_IN|CURL_CSELECT_OUT;
- break;
- default:
- return 0;
- }
-}
-
-static void php_http_curlm_timeout_callback(int socket, short action, void *event_data)
-{
- php_http_client_t *context = event_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "T");
-#endif
- if (curl->useevents) {
- CURLMcode rc;
- TSRMLS_FETCH_FROM_CTX(context->ts);
-
- /* ignore and use -1,0 on timeout */
- (void) socket;
- (void) action;
-
- while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished)));
-
- if (CURLM_OK != rc) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
- }
-
- php_http_curlm_responsehandler(context);
- }
-}
-
-static void php_http_curlm_event_callback(int socket, short action, void *event_data)
+void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action)
{
- php_http_client_t *context = event_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "E");
-#endif
- if (curl->useevents) {
- CURLMcode rc = CURLM_OK;
- TSRMLS_FETCH_FROM_CTX(context->ts);
-
- while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, socket, etoca(action), &curl->unfinished)));
-
- if (CURLM_OK != rc) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
- }
-
- php_http_curlm_responsehandler(context);
-
- /* remove timeout if there are no transfers left */
- if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- event_del(curl->timeout);
- }
- }
-}
-
-static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
-{
- php_http_client_t *context = socket_data;
- php_http_client_curl_t *curl = context->ctx;
+ CURLMcode rc;
+ php_http_client_curl_t *curl = client->ctx;
+ TSRMLS_FETCH_FROM_CTX(client->ts);
#if DBG_EVENTS
- fprintf(stderr, "S");
+ fprintf(stderr, "H");
#endif
- if (curl->useevents) {
- int events = EV_PERSIST;
- php_http_curlm_event_t *ev = assign_data;
- TSRMLS_FETCH_FROM_CTX(context->ts);
-
- if (!ev) {
- ev = ecalloc(1, sizeof(php_http_curlm_event_t));
- ev->context = context;
- curl_multi_assign(curl->handle->multi, sock, ev);
- } else {
- event_del(&ev->evnt);
- }
-
- switch (action) {
- case CURL_POLL_IN:
- events |= EV_READ;
- break;
- case CURL_POLL_OUT:
- events |= EV_WRITE;
- break;
- case CURL_POLL_INOUT:
- events |= EV_READ|EV_WRITE;
- break;
-
- case CURL_POLL_REMOVE:
- efree(ev);
- /* no break */
- case CURL_POLL_NONE:
- return 0;
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
- return -1;
- }
+ do {
+ rc = curl_multi_socket_action(curl->handle->multi, s, curl_action, &curl->unfinished);
+ } while (CURLM_CALL_MULTI_PERFORM == rc);
- event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context);
- event_add(&ev->evnt, NULL);
+ if (CURLM_OK != rc) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
}
- return 0;
-}
-
-static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
-{
- php_http_client_t *context = timer_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
-#endif
- if (curl->useevents) {
-
- if (timeout_ms < 0) {
- php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context);
- } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- struct timeval timeout;
-
- if (!event_initialized(curl->timeout)) {
- event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context);
- }
-
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
-
- event_add(curl->timeout, &timeout);
- }
- }
+ php_http_client_curl_responsehandler(client);
}
-#endif /* HAVE_EVENT */
-
/* curl options */
static php_http_options_t php_http_curle_options, php_http_curlm_options;
return SUCCESS;
}
+static ZEND_RESULT_CODE php_http_curle_option_set_cookiesession(php_http_option_t *opt, zval *val, void *userdata)
+{
+ php_http_client_curl_handler_t *curl = userdata;
+ CURL *ch = curl->handle;
+
+ if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIESESSION, (long) Z_BVAL_P(val))) {
+ return FAILURE;
+ }
+ if (Z_BVAL_P(val)) {
+ if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIELIST, "SESS")) {
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
#endif
#if PHP_HTTP_CURL_VERSION(7,40,0)
- if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_UNIX_SOCKETS)) {
+ if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
}
#endif
Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
}
#if PHP_HTTP_CURL_VERSION(7,43,0)
+ if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSPI) || PHP_HTTP_CURL_FEATURE(CURL_VERSION_GSSAPI))
if ((opt = php_http_option_register(registry, ZEND_STRL("service_name"), CURLOPT_SERVICE_NAME, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
}
/* cookiesession, don't load session cookies from cookiestore */
- php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL);
+ if ((opt = php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL))) {
+ opt->setter = php_http_curle_option_set_cookiesession;
+ }
/* cookiestore, read initial cookies from that file and store cookies back into that file */
if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
#endif
/* ssl */
- if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) {
- registry = &opt->suboptions;
+ if (PHP_HTTP_CURL_FEATURE(CURL_VERSION_SSL)) {
+ if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) {
+ registry = &opt->suboptions;
- if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- ZVAL_STRING(&opt->defval, "PEM", 0);
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- ZVAL_STRING(&opt->defval, "PEM", 0);
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- }
- php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
- php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
- if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) {
- ZVAL_BOOL(&opt->defval, 1);
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) {
- ZVAL_BOOL(&opt->defval, 1);
- opt->setter = php_http_curle_option_set_ssl_verifyhost;
- }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ ZVAL_STRING(&opt->defval, "PEM", 0);
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ ZVAL_STRING(&opt->defval, "PEM", 0);
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ }
+ php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
+ php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
+ if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) {
+ ZVAL_BOOL(&opt->defval, 1);
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) {
+ ZVAL_BOOL(&opt->defval, 1);
+ opt->setter = php_http_curle_option_set_ssl_verifyhost;
+ }
#if PHP_HTTP_CURL_VERSION(7,41,0) && (defined(PHP_HTTP_HAVE_OPENSSL) || defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_GNUTLS))
- php_http_option_register(registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, IS_BOOL);
+ php_http_option_register(registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, IS_BOOL);
#endif
- php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING);
- if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING);
+ if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
#ifdef PHP_HTTP_CURL_CAINFO
- ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0);
+ ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0);
#endif
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
#ifdef PHP_HTTP_CURL_CAPATH
- ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAPATH, 0);
+ ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAPATH, 0);
#endif
}
- if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
#if PHP_HTTP_CURL_VERSION(7,19,0)
- if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
# ifdef PHP_HTTP_HAVE_OPENSSL
- if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
# endif
#endif
#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT))
- php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL);
+ php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL);
#endif
#if PHP_HTTP_CURL_VERSION(7,36,0)
- if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, IS_BOOL))) {
- ZVAL_BOOL(&opt->defval, 1);
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, IS_BOOL))) {
- ZVAL_BOOL(&opt->defval, 1);
- }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, IS_BOOL))) {
+ ZVAL_BOOL(&opt->defval, 1);
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, IS_BOOL))) {
+ ZVAL_BOOL(&opt->defval, 1);
+ }
#endif
#if PHP_HTTP_CURL_VERSION(7,39,0)
- /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */
- if ((opt = php_http_option_register(registry, ZEND_STRL("pinned_publickey"), CURLOPT_PINNEDPUBLICKEY, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
- }
+ /* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */
+ if ((opt = php_http_option_register(registry, ZEND_STRL("pinned_publickey"), CURLOPT_PINNEDPUBLICKEY, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
+ }
#endif
#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP)
- if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthtype"), CURLOPT_TLSAUTH_TYPE, IS_LONG))) {
- opt->setter = php_http_curle_option_set_ssl_tlsauthtype;
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthuser"), CURLOPT_TLSAUTH_USERNAME, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- }
- if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthpass"), CURLOPT_TLSAUTH_PASSWORD, IS_STRING))) {
- opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
- }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthtype"), CURLOPT_TLSAUTH_TYPE, IS_LONG))) {
+ opt->setter = php_http_curle_option_set_ssl_tlsauthtype;
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthuser"), CURLOPT_TLSAUTH_USERNAME, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ }
+ if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthpass"), CURLOPT_TLSAUTH_PASSWORD, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ }
#endif
#if PHP_HTTP_CURL_VERSION(7,42,0) && (defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_DARWINSSL))
- php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, IS_BOOL);
+ php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, IS_BOOL);
#endif
+ }
}
}
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
zval tmp;
- CURLcode rc = CURLE_OK;
+ CURLcode rc = CURLE_UNKNOWN_OPTION;
ZEND_RESULT_CODE rv = SUCCESS;
TSRMLS_FETCH_FROM_CTX(curl->client->ts);
}
#endif
-#if PHP_HTTP_HAVE_EVENT
-static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, zend_bool enable)
+static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, php_http_client_curl_ops_t *ev_ops, zval *init_data)
{
php_http_client_curl_t *curl = h->ctx;
+ void *ev_ctx;
- if ((curl->useevents = enable)) {
- if (!curl->evbase) {
- curl->evbase = event_base_new();
- }
- if (!curl->timeout) {
- curl->timeout = ecalloc(1, sizeof(struct event));
+ if (ev_ops) {
+ if (!(ev_ctx = ev_ops->init(h, init_data))) {
+ return FAILURE;
}
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, h);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, h);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback);
+ curl->ev_ctx = ev_ctx;
+ curl->ev_ops = ev_ops;
} else {
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL);
+ if (curl->ev_ops) {
+ if (curl->ev_ctx) {
+ curl->ev_ops->dtor(&curl->ev_ctx);
+ }
+ curl->ev_ops = NULL;
+ }
}
return SUCCESS;
static ZEND_RESULT_CODE php_http_curlm_option_set_use_eventloop(php_http_option_t *opt, zval *value, void *userdata)
{
php_http_client_t *client = userdata;
+ php_http_client_curl_ops_t *ev_ops = NULL;
+ TSRMLS_FETCH_FROM_CTX(client->ts);
+
+ if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_class_entry TSRMLS_CC)) {
+ ev_ops = php_http_client_curl_user_ops_get();
+#if PHP_HTTP_HAVE_EVENT
+ } else if (value && z_is_true(value)) {
+ ev_ops = php_http_client_curl_event_ops_get();
+#endif
+ }
+
+ return php_http_curlm_use_eventloop(client, ev_ops, value);
+}
+
+static ZEND_RESULT_CODE php_http_curlm_option_set_share_cookies(php_http_option_t *opt, zval *value, void *userdata)
+{
+ php_http_client_t *client = userdata;
+ php_http_client_curl_t *curl = client->ctx;
+ CURLSHcode rc;
+
+ if (Z_BVAL_P(value)) {
+ rc = curl_share_setopt(curl->handle->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
+ } else {
+ rc = curl_share_setopt(curl->handle->share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE);
+ }
+
+ if (CURLSHE_OK != rc) {
+ TSRMLS_FETCH_FROM_CTX(client->ts);
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_share_strerror(rc));
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+#if PHP_HTTP_CURL_VERSION(7,23,0)
+static ZEND_RESULT_CODE php_http_curlm_option_set_share_ssl(php_http_option_t *opt, zval *value, void *userdata)
+{
+ php_http_client_t *client = userdata;
+ php_http_client_curl_t *curl = client->ctx;
+ CURLSHcode rc;
+
+ if (Z_BVAL_P(value)) {
+ rc = curl_share_setopt(curl->handle->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
+ } else {
+ rc = curl_share_setopt(curl->handle->share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_SSL_SESSION);
+ }
- return php_http_curlm_use_eventloop(client, value && Z_BVAL_P(value));
+ if (CURLSHE_OK != rc) {
+ TSRMLS_FETCH_FROM_CTX(client->ts);
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_share_strerror(rc));
+ return FAILURE;
+ }
+ return SUCCESS;
}
#endif
}
#endif
/* events */
-#if PHP_HTTP_HAVE_EVENT
- if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, IS_BOOL))) {
+ if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, 0))) {
opt->setter = php_http_curlm_option_set_use_eventloop;
}
+ /* share */
+ if ((opt = php_http_option_register(registry, ZEND_STRL("share_cookies"), 0, IS_BOOL))) {
+ opt->setter = php_http_curlm_option_set_share_cookies;
+ ZVAL_BOOL(&opt->defval, 1);
+ }
+#if PHP_HTTP_CURL_VERSION(7,23,0)
+ if ((opt = php_http_option_register(registry, ZEND_STRL("share_ssl"), 0, IS_BOOL))) {
+ opt->setter = php_http_curlm_option_set_share_ssl;
+ ZVAL_BOOL(&opt->defval, 1);
+ }
#endif
}
case IS_BOOL:
if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) Z_BVAL_P(val)))) {
rv = FAILURE;
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_multi_strerror(rc));
}
break;
case IS_LONG:
if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, Z_LVAL_P(val)))) {
rv = FAILURE;
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_multi_strerror(rc));
}
break;
default:
rv = FAILURE;
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s", opt->name.s);
break;
}
}
zval_ptr_dtor(&val);
}
- if (rv != SUCCESS) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not set option %s (%s)", opt->name.s, curl_easy_strerror(rc));
- }
return rv;
}
curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback);
curl_easy_setopt(handle, CURLOPT_XFERINFODATA, handler);
#else
- curl_easy_setopt(handle->multi, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback);
- curl_easy_setopt(handle->multi, CURLOPT_PROGRESSDATA, handler);
+ curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback);
+ curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler);
#endif
curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, handler);
#if PHP_HTTP_CURL_VERSION(7,32,0)
curl_easy_setopt(handler->handle, CURLOPT_XFERINFOFUNCTION, NULL);
#else
- curl_easy_setopt(handler->handle->multi, CURLOPT_PROGRESSFUNCTION, NULL);
+ curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL);
#endif
curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL);
php_http_client_curl_t *curl = h->ctx;
TSRMLS_FETCH_FROM_CTX(h->ts);
-#if PHP_HTTP_HAVE_EVENT
- if (curl->timeout) {
- if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- event_del(curl->timeout);
- }
- efree(curl->timeout);
- curl->timeout = NULL;
+ if (curl->ev_ops) {
+ curl->ev_ops->dtor(&curl->ev_ctx);
+ curl->ev_ops = NULL;
}
- if (curl->evbase) {
- event_base_free(curl->evbase);
- curl->evbase = NULL;
- }
-#endif
curl->unfinished = 0;
php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC);
php_http_client_curl_handler_t *handler = enqueue->opaque;
TSRMLS_FETCH_FROM_CTX(h->ts);
+ if (h->callback.depth) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not dequeue request while executing callbacks");
+ return FAILURE;
+ }
+
php_http_client_curl_handler_clear(handler);
if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) {
zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue);
}
}
-static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout)
-{
- if ((CURLM_OK == curl_multi_timeout(curl->handle->multi, &max_tout)) && (max_tout > 0)) {
- timeout->tv_sec = max_tout / 1000;
- timeout->tv_usec = (max_tout % 1000) * 1000;
- } else {
- timeout->tv_sec = 0;
- timeout->tv_usec = 1000;
- }
-}
-
#ifdef PHP_WIN32
# define SELECT_ERROR SOCKET_ERROR
#else
struct timeval timeout;
php_http_client_curl_t *curl = h->ctx;
-#if PHP_HTTP_HAVE_EVENT
- if (curl->useevents) {
- if (!event_initialized(curl->timeout)) {
- event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, h);
- } else if (custom_timeout && timerisset(custom_timeout)) {
- event_add(curl->timeout, custom_timeout);
- } else if (!event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- php_http_client_curl_get_timeout(curl, 1000, &timeout);
- event_add(curl->timeout, &timeout);
- }
-
- event_base_loop(curl->evbase, EVLOOP_ONCE);
-
- return SUCCESS;
+ if (curl->ev_ops) {
+ return curl->ev_ops->wait(curl->ev_ctx, custom_timeout);
}
-#endif
FD_ZERO(&R);
FD_ZERO(&W);
{
php_http_client_curl_t *curl = h->ctx;
-#if PHP_HTTP_HAVE_EVENT
- if (curl->useevents) {
- event_base_loop(curl->evbase, EVLOOP_NONBLOCK);
- } else
-#endif
- while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle->multi, &curl->unfinished));
+ if (curl->ev_ops) {
+ curl->ev_ops->once(curl->ev_ctx);
+ } else {
+ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle->multi, &curl->unfinished));
+ }
- php_http_curlm_responsehandler(h);
+ php_http_client_curl_responsehandler(h);
return curl->unfinished;
static ZEND_RESULT_CODE php_http_client_curl_exec(php_http_client_t *h)
{
-#if PHP_HTTP_HAVE_EVENT
php_http_client_curl_t *curl = h->ctx;
-#endif
TSRMLS_FETCH_FROM_CTX(h->ts);
-#if PHP_HTTP_HAVE_EVENT
- if (curl->useevents) {
- php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
- do {
- int ev_rc = event_base_dispatch(curl->evbase);
-
-#if DBG_EVENTS
- fprintf(stderr, "%c", "X.0"[ev_rc+1]);
-#endif
+ if (curl->ev_ops) {
+ return curl->ev_ops->exec(curl->ev_ctx);
+ }
- if (ev_rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error in event_base_dispatch()");
- return FAILURE;
- }
- } while (curl->unfinished && !EG(exception));
- } else
-#endif
- {
- while (php_http_client_curl_once(h) && !EG(exception)) {
- if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
+ while (php_http_client_curl_once(h) && !EG(exception)) {
+ if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
#ifdef PHP_WIN32
- /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
+ /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
#else
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
#endif
- return FAILURE;
- }
+ return FAILURE;
}
}
case PHP_HTTP_CLIENT_OPT_USE_EVENTS:
#if PHP_HTTP_HAVE_EVENT
- return php_http_curlm_use_eventloop(h, *(zend_bool *) arg);
+ return php_http_curlm_use_eventloop(h, (*(zend_bool *) arg)
+ ? php_http_client_curl_event_ops_get()
+ : NULL, NULL);
break;
#endif
return &php_http_client_curl_ops;
}
+
PHP_MINIT_FUNCTION(http_client_curl)
{
curl_version_info_data *info;