#include "php_http_api.h"
#include "php_http_client.h"
-#if 1||PHP_HTTP_HAVE_CURL
+#if PHP_HTTP_HAVE_CURL
#if PHP_HTTP_HAVE_EVENT
# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
static int php_http_curle_seek_callback(void *userdata, curl_off_t offset, int origin)
{
php_http_message_body_t *body = userdata;
- TSRMLS_FETCH_FROM_CTX(body->ts);
if (!body) {
return 1;
case CURLSSLBACKEND_QSOSSL:
backend = "qsossl";
break;
-#endif
+#else
case CURLSSLBACKEND_GSKIT:
backend = "gskit";
break;
+#endif
case CURLSSLBACKEND_POLARSSL:
backend = "polarssl";
break;
}
#endif
-#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
+#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))
{
int i;
zval ci_array, subarray;
return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle;
}
-static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_handler_t *h TSRMLS_DC)
+static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_handler_t *h)
{
php_http_message_t *response;
php_http_header_parser_t parser;
zval *zh;
- response = php_http_message_init(NULL, 0, h->response.body TSRMLS_CC);
- php_http_header_parser_init(&parser TSRMLS_CC);
- 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);
+ response = php_http_message_init(NULL, 0, h->response.body);
+ php_http_header_parser_init(&parser);
+ while (h->response.headers.used) {
+ php_http_header_parser_state_t st = 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);
+ if (PHP_HTTP_HEADER_PARSER_STATE_FAILURE == st) {
+ break;
+ }
+ }
php_http_header_parser_dtor(&parser);
/* move body to right message */
while (ptr->parent) {
ptr = ptr->parent;
}
+ php_http_message_body_free(&response->body);
response->body = ptr->body;
ptr->body = NULL;
}
static void php_http_curlm_responsehandler(php_http_client_t *context)
{
- int remaining = 0;
+ int err_count = 0, remaining = 0;
+ php_http_curle_storage_t *st, *err = NULL;
php_http_client_enqueue_t *enqueue;
php_http_client_curl_t *curl = context->ctx;
if (msg && CURLMSG_DONE == msg->msg) {
if (CURLE_OK != msg->data.result) {
- php_http_curle_storage_t *st = php_http_curle_get_storage(msg->easy_handle);
- php_error_docref(NULL, E_WARNING, "%s; %s (%s)", curl_easy_strerror(st->errorcode = msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url));
+ st = php_http_curle_get_storage(msg->easy_handle);
+ st->errorcode = msg->data.result;
+
+ /* defer the warnings/exceptions, so the callback is still called for this request */
+ if (!err) {
+ err = ecalloc(remaining + 1, sizeof(*err));
+ }
+ memcpy(&err[err_count], st, sizeof(*st));
+ if (st->url) {
+ err[err_count].url = estrdup(st->url);
+ }
+ err_count++;
}
if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) {
php_http_client_curl_handler_t *handler = enqueue->opaque;
- php_http_message_t *response = php_http_curlm_responseparser(handler TSRMLS_CC);
+ php_http_message_t *response = php_http_curlm_responseparser(handler);
if (response) {
context->callback.response.func(context->callback.response.arg, context, &handler->queue, &response);
}
}
} while (remaining);
+
+ if (err_count) {
+ int i = 0;
+
+ do {
+ php_error_docref(NULL, E_WARNING, "%s; %s (%s)", curl_easy_strerror(err[i].errorcode), err[i].errorbuffer, STR_PTR(err[i].url));
+ if (err[i].url) {
+ efree(err[i].url);
+ }
+ } while (++i < err_count);
+
+ efree(err);
+ }
}
#if PHP_HTTP_HAVE_EVENT
/* curl options */
-static php_http_options_t php_http_curle_options;
+static php_http_options_t php_http_curle_options, php_http_curlm_options;
#define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN 0x0001
#define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR 0x0002
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
+#if !PHP_HTTP_CURL_VERSION(7,21,6)
+# define CURLOPT_ACCEPT_ENCODING CURLOPT_ENCODING
+#endif
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ACCEPT_ENCODING, Z_TYPE_P(val) == IS_TRUE ? "" : NULL)) {
return FAILURE;
}
{
if (header_key.key) {
zend_string *zs = zval_get_string(header_val);
+
php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, zs->val);
+ zend_string_release(zs);
+
php_http_buffer_fix(&header);
curl->options.proxyheaders = curl_slist_append(curl->options.proxyheaders, header.data);
php_http_buffer_reset(&header);
- zend_string_release(zs);
+
}
}
ZEND_HASH_FOREACH_END();
opt->setter = php_http_curle_option_set_proxyheader;
}
#endif
+#if PHP_HTTP_CURL_VERSION(7,43,0)
+ if ((opt = php_http_option_register(registry, ZEND_STRL("proxy_service_name"), CURLOPT_PROXY_SERVICE_NAME, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ }
+#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))) {
if ((opt = php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG))) {
Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
}
+#if PHP_HTTP_CURL_VERSION(7,43,0)
+ if ((opt = php_http_option_register(registry, ZEND_STRL("service_name"), CURLOPT_SERVICE_NAME, IS_STRING))) {
+ opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
+ }
+#endif
/* redirects */
if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) {
opt->setter = php_http_curle_option_set_ssl_verifyhost;
}
#if PHP_HTTP_CURL_VERSION(7,41,0)
- 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))) {
}
# endif
#endif
-#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
- php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL);
+#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))
+ if ((opt = php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL))) {
+ ZVAL_FALSE(&opt->defval);
+ }
#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))) {
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);
#endif
}
}
zval *option;
if ((option = php_http_option_get(opt, options, NULL))) {
- Z_TRY_ADDREF_P(option);
- convert_to_explicit_type_ex(option, opt->type);
- zend_hash_update(&curl->options.cache, opt->name, option);
+ zval zopt;
+
+ ZVAL_DUP(&zopt, option);
+ convert_to_explicit_type(&zopt, opt->type);
+ zend_hash_update(&curl->options.cache, opt->name, &zopt);
+ return zend_hash_find(&curl->options.cache, opt->name);
}
return option;
}
return rv;
}
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_t *opt, zval *value, void *userdata)
+{
+ php_http_client_t *client = userdata;
+ php_http_client_curl_t *curl = client->ctx;
+ CURLM *ch = curl->handle;
+ HashTable tmp_ht;
+ char **bl = NULL;
+
+ /* array of char *, ending with a NULL */
+ if (value && Z_TYPE_P(value) != IS_NULL) {
+ zval *entry;
+ HashTable *ht = HASH_OF(value);
+ int c = zend_hash_num_elements(ht);
+ char **ptr = ecalloc(c + 1, sizeof(char *));
+
+ bl = ptr;
+
+ zend_hash_init(&tmp_ht, c, NULL, ZVAL_PTR_DTOR, 0);
+ array_join(ht, &tmp_ht, 0, ARRAY_JOIN_STRINGIFY);
+
+ ZEND_HASH_FOREACH_VAL(&tmp_ht, entry)
+ {
+ *ptr++ = Z_STRVAL_P(entry);
+ }
+ ZEND_HASH_FOREACH_END();
+ }
+
+ if (CURLM_OK != curl_multi_setopt(ch, opt->option, bl)) {
+ if (bl) {
+ efree(bl);
+ zend_hash_destroy(&tmp_ht);
+ }
+ return FAILURE;
+ }
+
+ if (bl) {
+ efree(bl);
+ zend_hash_destroy(&tmp_ht);
+ }
+ return SUCCESS;
+}
+#endif
+
+#if PHP_HTTP_HAVE_EVENT
+static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, zend_bool enable)
+{
+ php_http_client_curl_t *curl = h->ctx;
+
+ if ((curl->useevents = enable)) {
+ if (!curl->evbase) {
+ curl->evbase = event_base_new();
+ }
+ if (!curl->timeout) {
+ curl->timeout = ecalloc(1, sizeof(struct event));
+ }
+ curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, h);
+ curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback);
+ curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h);
+ curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback);
+ } else {
+ curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, NULL);
+ curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, NULL);
+ curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, NULL);
+ curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, 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;
+
+ return php_http_curlm_use_eventloop(client, value && Z_TYPE_P(value) == IS_TRUE);
+}
+#endif
+
+static void php_http_curlm_options_init(php_http_options_t *registry)
+{
+ php_http_option_t *opt;
+
+ /* set size of connection cache */
+ if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLMOPT_MAXCONNECTS, IS_LONG))) {
+ /* -1 == default, 0 == unlimited */
+ ZVAL_LONG(&opt->defval, -1);
+ }
+ /* set max number of connections to a single host */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ php_http_option_register(registry, ZEND_STRL("max_host_connections"), CURLMOPT_MAX_HOST_CONNECTIONS, IS_LONG);
+#endif
+ /* maximum number of requests in a pipeline */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ if ((opt = php_http_option_register(registry, ZEND_STRL("max_pipeline_length"), CURLMOPT_MAX_PIPELINE_LENGTH, IS_LONG))) {
+ ZVAL_LONG(&opt->defval, 5);
+ }
+#endif
+ /* max simultaneously open connections */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ php_http_option_register(registry, ZEND_STRL("max_total_connections"), CURLMOPT_MAX_TOTAL_CONNECTIONS, IS_LONG);
+#endif
+ /* enable/disable HTTP pipelining */
+ php_http_option_register(registry, ZEND_STRL("pipelining"), CURLMOPT_PIPELINING, _IS_BOOL);
+ /* chunk length threshold for pipelining */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ php_http_option_register(registry, ZEND_STRL("chunk_length_penalty_size"), CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, IS_LONG);
+#endif
+ /* size threshold for pipelining penalty */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ php_http_option_register(registry, ZEND_STRL("content_length_penalty_size"), CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, IS_LONG);
+#endif
+ /* pipelining server blacklist */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_server_bl"), CURLMOPT_PIPELINING_SERVER_BL, IS_ARRAY))) {
+ opt->setter = php_http_curlm_option_set_pipelining_bl;
+ }
+#endif
+ /* pipelining host blacklist */
+#if PHP_HTTP_CURL_VERSION(7,30,0)
+ if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_site_bl"), CURLMOPT_PIPELINING_SITE_BL, IS_ARRAY))) {
+ opt->setter = php_http_curlm_option_set_pipelining_bl;
+ }
+#endif
+ /* events */
+#if PHP_HTTP_HAVE_EVENT
+ if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, _IS_BOOL))) {
+ opt->setter = php_http_curlm_option_set_use_eventloop;
+ }
+#endif
+}
+
+static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval *val, void *userdata)
+{
+ php_http_client_t *client = userdata;
+ php_http_client_curl_t *curl = client->ctx;
+ CURLM *ch = curl->handle;
+ zval *orig = val;
+ CURLMcode rc = CURLM_UNKNOWN_OPTION;
+ ZEND_RESULT_CODE rv = SUCCESS;
+
+ if (!val) {
+ val = &opt->defval;
+ } else if (opt->type && Z_TYPE_P(val) != opt->type && !(Z_TYPE_P(val) == IS_NULL && opt->type == IS_ARRAY)) {
+ zval zopt;
+
+ ZVAL_DUP(&zopt, val);
+ convert_to_explicit_type(&zopt, opt->type);
+
+ val = &zopt;
+ }
+
+ if (opt->setter) {
+ rv = opt->setter(opt, val, client);
+ } else {
+ switch (opt->type) {
+ case _IS_BOOL:
+ if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) zend_is_true(val)))) {
+ rv = FAILURE;
+ }
+ break;
+ case IS_LONG:
+ if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, Z_LVAL_P(val)))) {
+ rv = FAILURE;
+ }
+ break;
+ default:
+ rv = FAILURE;
+ break;
+ }
+ }
+
+ if (val && val != orig && val != &opt->defval) {
+ zval_ptr_dtor(val);
+ }
+
+ if (rv != SUCCESS) {
+ php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc));
+ }
+ return rv;
+}
/* client ops */
php_http_url_to_string(PHP_HTTP_INFO(msg).request.url, &storage->url, NULL, 1);
curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url);
- /* request method */
- switch (php_http_select_str(PHP_HTTP_INFO(msg).request.method, 4, "GET", "HEAD", "POST", "PUT")) {
- case 0:
- curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1L);
- break;
-
- case 1:
- curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L);
- break;
-
- case 2:
- curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
- break;
-
- case 3:
- curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
- break;
-
- default: {
- if (PHP_HTTP_INFO(msg).request.method) {
- curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method);
- } else {
- php_error_docref(NULL, E_WARNING, "Cannot use empty request method");
- return FAILURE;
- }
- break;
- }
- }
-
/* apply options */
php_http_options_apply(&php_http_curle_options, enqueue->options, curl);
curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body);
curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size);
curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size);
+ curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
} else {
curl_easy_setopt(curl->handle, CURLOPT_SEEKDATA, NULL);
curl_easy_setopt(curl->handle, CURLOPT_READDATA, NULL);
curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, 0L);
}
+ /*
+ * Always use CUSTOMREQUEST, else curl won't send any request body for GET etc.
+ * See e.g. bug #69313.
+ *
+ * Here's what curl does:
+ * - CURLOPT_HTTPGET: ignore request body
+ * - CURLOPT_UPLOAD: set "Expect: 100-continue" header
+ * - CURLOPT_POST: set "Content-Type: application/x-www-form-urlencoded" header
+ * Now select the least bad.
+ *
+ * See also https://tools.ietf.org/html/rfc7231#section-5.1.1
+ */
+ if (PHP_HTTP_INFO(msg).request.method) {
+ if (!strcasecmp("PUT", PHP_HTTP_INFO(msg).request.method)) {
+ curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
+ } else {
+ curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method);
+ }
+ } else {
+ php_error_docref(NULL, E_WARNING, "Cannot use empty request method");
+ return FAILURE;
+ }
+
return SUCCESS;
}
php_http_buffer_dtor(&handler->options.cookies);
zend_hash_destroy(&handler->options.cache);
+#if PHP_HTTP_CURL_VERSION(7,21,3)
+ if (handler->options.resolve) {
+ curl_slist_free_all(handler->options.resolve);
+ handler->options.resolve = NULL;
+ }
+#endif
+
if (handler->options.headers) {
curl_slist_free_all(handler->options.headers);
handler->options.headers = NULL;
}
+ if (handler->options.proxyheaders) {
+ curl_slist_free_all(handler->options.proxyheaders);
+ handler->options.proxyheaders = NULL;
+ }
+
efree(handler);
}
php_http_client_curl_handler_dtor(handler);
}
-static php_resource_factory_t *create_rf(php_http_url_t *url)
+static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
{
- php_persistent_handle_factory_t *pf;
+ php_persistent_handle_factory_t *pf = NULL;
php_resource_factory_t *rf = NULL;
- zend_string *id;
- char *id_str = NULL;
- size_t id_len;
+ php_http_url_t *url = enqueue->request->http.info.request.url;
if (!url || (!url->host && !url->path)) {
php_error_docref(NULL, E_WARNING, "Cannot request empty URL");
return NULL;
}
- id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), url->port ? url->port : 80);
- id = php_http_cs2zs(id_str, id_len);
+ /* only if the client itself is setup for persistence */
+ if (php_resource_factory_is_persistent(h->rf)) {
+ zend_string *id;
+ char *id_str = NULL;
+ size_t id_len;
+ int port = url->port ? url->port : 80;
+ zval *zport;
+
+ if ((zport = zend_hash_str_find(enqueue->options, ZEND_STRL("port")))) {
+ zend_long lport = zval_get_long(zport);
- pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, NULL);
- zend_string_release(id);
+ if (lport > 0) {
+ port = lport;
+ }
+ }
+
+ id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), port);
+ id = php_http_cs2zs(id_str, id_len);
+ pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, NULL);
+ zend_string_release(id);
+ }
if (pf) {
- rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void*)) php_persistent_handle_abandon);
+ rf = php_persistent_handle_resource_factory_init(NULL, pf);
} else {
rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL);
}
php_http_client_progress_state_t *progress;
php_resource_factory_t *rf;
- rf = create_rf(enqueue->request->http.info.request.url);
+ rf = create_rf(h, enqueue);
if (!rf) {
return FAILURE;
}
php_error_docref(NULL, E_ERROR, "Error in event_base_dispatch()");
return FAILURE;
}
- } while (curl->unfinished);
+ } while (curl->unfinished && !EG(exception));
} else
#endif
{
- while (php_http_client_curl_once(h)) {
+ 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_http_client_curl_t *curl = h->ctx;
switch (opt) {
+ case PHP_HTTP_CLIENT_OPT_CONFIGURATION:
+ return php_http_options_apply(&php_http_curlm_options, (HashTable *) arg, h);
+ break;
+
case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING:
if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) {
return FAILURE;
case PHP_HTTP_CLIENT_OPT_USE_EVENTS:
#if PHP_HTTP_HAVE_EVENT
- if ((curl->useevents = *((zend_bool *) arg))) {
- if (!curl->evbase) {
- curl->evbase = event_base_new();
- }
- if (!curl->timeout) {
- curl->timeout = ecalloc(1, sizeof(struct event));
- }
- curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, h);
- curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback);
- curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h);
- curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback);
- } else {
- curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, NULL);
- curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, NULL);
- curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, NULL);
- curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, NULL);
- }
+ return php_http_curlm_use_eventloop(h, *(zend_bool *) arg);
break;
#endif
return SUCCESS;
}
+static int apply_available_options(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ php_http_option_t *opt = Z_PTR_P(pDest);
+ HashTable *ht;
+ zval entry;
+ int c;
+
+ ht = va_arg(args, HashTable*);
+
+ if ((c = zend_hash_num_elements(&opt->suboptions.options))) {
+ array_init_size(&entry, c);
+ zend_hash_apply_with_arguments(&opt->suboptions.options, apply_available_options, 1, Z_ARRVAL(entry));
+ } else {
+ /* catch deliberate NULL options */
+ if (Z_TYPE(opt->defval) == IS_STRING && !Z_STRVAL(opt->defval)) {
+ ZVAL_NULL(&entry);
+ } else {
+ ZVAL_ZVAL(&entry, &opt->defval, 1, 0);
+ }
+ }
+
+ if (hash_key->key) {
+ zend_hash_update(ht, hash_key->key, &entry);
+ } else {
+ zend_hash_index_update(ht, hash_key->h, &entry);
+ }
+
+ return ZEND_HASH_APPLY_KEEP;
+}
+
static ZEND_RESULT_CODE php_http_client_curl_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void **res)
{
php_http_client_enqueue_t *enqueue;
}
break;
+ case PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS:
+ zend_hash_apply_with_arguments(&php_http_curle_options.options, apply_available_options, 1, *(HashTable **) res);
+ break;
+
+ case PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION:
+ zend_hash_apply_with_arguments(&php_http_curlm_options.options, apply_available_options, 1, *(HashTable **) res);
+ break;
+
default:
break;
}
php_http_curle_options_init(options);
}
+ if ((options = php_http_options_init(&php_http_curlm_options, 1))) {
+ options->getter = php_http_option_get;
+ options->setter = php_http_curlm_set_option;
+
+ php_http_curlm_options_init(options);
+ }
/*
* HTTP Protocol Version Constants
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT, CONST_CS|CONST_PERSISTENT);
-#if PHP_HTTP_CURL_VERSION(7,21,4)
+#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "TLSAUTH_SRP", CURL_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT);
#endif
zend_string_release(PHP_HTTP_G->client.curl.driver.driver_name);
php_http_options_dtor(&php_http_curle_options);
+ php_http_options_dtor(&php_http_curlm_options);
return SUCCESS;
}