From: Michael Wallner Date: Thu, 28 Mar 2013 20:21:51 +0000 (+0000) Subject: codename: client meltdown X-Git-Tag: RELEASE_2_1_0_RC3~10^2^2~33 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=f753226f1f45e10ef3916256ec1bc0416c8644a8;ds=sidebyside codename: client meltdown --- diff --git a/bench_select_vs_event.php b/bench_select_vs_event.php index 457f2d3..2e38861 100644 --- a/bench_select_vs_event.php +++ b/bench_select_vs_event.php @@ -1,66 +1,5 @@ "pool", "requestClass" => "request")); - -class pool extends HttpRequestPool { - private $url; - private $cnt; - - private $factory; - - static function fetch($factory, $url, $n, $c, $e, $p) { - $pool = $factory->createPool(); - $pool->factory = $factory; - $pool->url = $url; - $pool->cnt = $n; - - $pool->enablePipelining($p); - $pool->enableEvents($e); - - for ($i = 0; $i < $c; ++$i) { - $pool->push(); - } - try { - $pool->send(); - } catch (Exception $ex) { - echo $ex, "\n"; - } - } - - function push() { - if ($this->cnt > 0) { - $this->factory->createRequest()->init($this, $this->url)->id = $this->cnt--; - } - } -} - -class request extends HttpRequest implements SplObserver { - static $counter = 0; - - public $id; - private $pool; - - function init(pool $pool, $url) { - $this->setUrl($url); - $this->pool = $pool; - $this->attach($this); - $pool->attach($this); - return $this; - } - - function update(SplSubject $r) { - if ($r->getProgress()->finished) { - ++self::$counter; - $this->pool->detach($this); - $this->detach($this); - $this->pool->push(); - } - } -} - function usage($e = null) { global $argv; if ($e) { @@ -71,6 +10,17 @@ function usage($e = null) { exit(-1); } +function push($client, $url, &$n) { + if ($n-- > 0) { + $req = new http\Client\Request("GET", $url); + $client->enqueue($req, function($response) use ($client, $req, $url, &$n) { + global $count; ++$count; + push($client, $url, $n); + return true; // dequeue + }); + } +} + isset($argv) or $argv = $_SERVER['argv']; defined('STDERR') or define('STDERR', fopen('php://stderr', 'w')); @@ -79,16 +29,25 @@ isset($opts["u"]) or $opts["u"] = "http://localhost/"; isset($opts["c"]) or $opts["c"] = 10; isset($opts["n"]) or $opts["n"] = 1000; -try { - ($c=$factory->createRequest($opts["u"])->send()->getResponseCode()) == 200 or usage("Received response code $c"); -} catch (Exception $ex) { - usage($ex->getMessage()); +$argc > 1 or usage(); +var_Dump($opts); +$time = microtime(true); +$count = 0; +$client = new http\Client; + +$client->enablePipelining($opts["p"]===false); +$client->enableEvents($opts["e"]===false); + +for ($i = 0, $x = $opts["n"]; $i < $opts["c"]; ++$i) { + push($client, $opts["u"], $x); } -$argc > 1 or usage(); +try { + $client->send(); +} catch (Exception $e) { + echo $e; +} -$time = microtime(true); -pool::fetch($factory, $opts["u"], $opts["n"], $opts["c"], isset($opts["e"]), isset($opts["p"])); printf("\n> %10.6fs (%3.2fM)\n", microtime(true)-$time, memory_get_peak_usage(true)/1024/1024); -request::$counter == $opts["n"] or printf("\nOnly %d finished\n", request::$counter); +$count == $opts["n"] or printf("\nOnly %d finished\n", $count); diff --git a/config9.m4 b/config9.m4 index dbceef3..e32d146 100644 --- a/config9.m4 +++ b/config9.m4 @@ -339,7 +339,7 @@ dnl ---- AC_MSG_CHECKING([for libevent version, roughly]) if test -f "$EVENT_DIR/include/event2/event.h"; then - EVENT_VER="`$EGREP _EVENT_VERSION $EVENT_DIR/include/event2/event.h | $AWK '{print $3}'`" + EVENT_VER="`$EGREP _EVENT_VERSION $EVENT_DIR/include/event2/event-config.h | $AWK '{print $3}'`" AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [1], [ ]) else AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ]) @@ -462,13 +462,7 @@ dnl ---- php_http_buffer.c \ php_http.c \ php_http_client.c \ - php_http_curl_client.c \ - php_http_client_datashare.c \ - php_http_curl_client_datashare.c \ - php_http_client_factory.c \ - php_http_client_interface.c \ - php_http_client_pool.c \ - php_http_curl_client_pool.c \ + php_http_client_curl.c \ php_http_client_request.c \ php_http_client_response.c \ php_http_cookie.c \ diff --git a/package.xml b/package.xml index 6e3cf07..d345f10 100644 --- a/package.xml +++ b/package.xml @@ -28,7 +28,7 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be 2012-12-31 - 2.0.0beta5 + 2.0.0dev 2.0.0 @@ -37,13 +37,6 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be BSD, revised 80% test coverage http://goo.gl/VmyIW -* Fixed build with libcurl <= 7.21.3 -* Fixed var_dump of http\Message with inherited userland properties with increased access level -+ Added http\Header::getParams() -+ Added simple support for escapes and quotes in the params parser -+ Added support for sending http\Env\Response over PHP streams -+ Added message body reference counting ]]> @@ -59,15 +52,9 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - - - - - - - - + + @@ -75,12 +62,6 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - - - - - - @@ -130,7 +111,6 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - @@ -140,7 +120,6 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - @@ -153,7 +132,6 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - @@ -170,7 +148,6 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be - @@ -181,17 +158,15 @@ Extended HTTP support. Again. Keep in mind that it's got the major version 2, be + - - - diff --git a/php_http.c b/php_http.c index 11033e5..914d695 100644 --- a/php_http.c +++ b/php_http.c @@ -167,18 +167,12 @@ PHP_MINIT_FUNCTION(http) || SUCCESS != PHP_MINIT_CALL(http_message) || SUCCESS != PHP_MINIT_CALL(http_message_body) || SUCCESS != PHP_MINIT_CALL(http_querystring) - || SUCCESS != PHP_MINIT_CALL(http_client_interface) || SUCCESS != PHP_MINIT_CALL(http_client) || SUCCESS != PHP_MINIT_CALL(http_client_request) || SUCCESS != PHP_MINIT_CALL(http_client_response) - || SUCCESS != PHP_MINIT_CALL(http_client_datashare) - || SUCCESS != PHP_MINIT_CALL(http_client_pool) - || SUCCESS != PHP_MINIT_CALL(http_client_factory) #if PHP_HTTP_HAVE_CURL || SUCCESS != PHP_MINIT_CALL(http_curl) - || SUCCESS != PHP_MINIT_CALL(http_curl_client) - || SUCCESS != PHP_MINIT_CALL(http_curl_client_pool) - || SUCCESS != PHP_MINIT_CALL(http_curl_client_datashare) + || SUCCESS != PHP_MINIT_CALL(http_client_curl) #endif || SUCCESS != PHP_MINIT_CALL(http_url) || SUCCESS != PHP_MINIT_CALL(http_env) @@ -201,10 +195,10 @@ PHP_MSHUTDOWN_FUNCTION(http) if (0 || SUCCESS != PHP_MSHUTDOWN_CALL(http_message) #if PHP_HTTP_HAVE_CURL - || SUCCESS != PHP_MSHUTDOWN_CALL(http_curl_client) + || SUCCESS != PHP_MSHUTDOWN_CALL(http_client_curl) || SUCCESS != PHP_MSHUTDOWN_CALL(http_curl) #endif - || SUCCESS != PHP_MSHUTDOWN_CALL(http_client_factory) + || SUCCESS != PHP_MSHUTDOWN_CALL(http_client) ) { return FAILURE; } @@ -219,7 +213,7 @@ PHP_RINIT_FUNCTION(http) if (0 || SUCCESS != PHP_RINIT_CALL(http_env) #if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT - || SUCCESS != PHP_RINIT_CALL(http_curl_client_pool) + || SUCCESS != PHP_RINIT_CALL(http_client_curl) #endif ) { return FAILURE; @@ -232,7 +226,7 @@ PHP_RSHUTDOWN_FUNCTION(http) { if (0 #if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT - || SUCCESS != PHP_RSHUTDOWN_CALL(http_curl_client_pool) + || SUCCESS != PHP_RSHUTDOWN_CALL(http_client_curl) #endif || SUCCESS != PHP_RSHUTDOWN_CALL(http_env) ) { diff --git a/php_http.h b/php_http.h index 501a60f..40ecfb4 100644 --- a/php_http.h +++ b/php_http.h @@ -13,7 +13,7 @@ #ifndef PHP_EXT_HTTP_H #define PHP_EXT_HTTP_H -#define PHP_HTTP_EXT_VERSION "2.0.0beta4" +#define PHP_HTTP_EXT_VERSION "2.0.0dev" zend_module_entry http_module_entry; #define phpext_http_ptr &http_module_entry diff --git a/php_http_api.h b/php_http_api.h index 31e70df..631b620 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -96,17 +96,11 @@ typedef int STATUS; #include "php_http_object.h" #include "php_http_params.h" #include "php_http_querystring.h" -#include "php_http_client_interface.h" #include "php_http_client.h" #include "php_http_curl.h" #include "php_http_client_request.h" #include "php_http_client_response.h" -#include "php_http_curl_client.h" -#include "php_http_client_pool.h" -#include "php_http_curl_client_pool.h" -#include "php_http_client_datashare.h" -#include "php_http_curl_client_datashare.h" -#include "php_http_client_factory.h" +#include "php_http_client_curl.h" #include "php_http_url.h" #include "php_http_version.h" diff --git a/php_http_client.c b/php_http_client.c index 4d109bd..c307221 100644 --- a/php_http_client.c +++ b/php_http_client.c @@ -1,19 +1,136 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - #include "php_http_api.h" +#include "php_http_client.h" #include -#include + +/* + * array of name => php_http_client_driver_t* + */ +static HashTable php_http_client_drivers; + +PHP_HTTP_API STATUS php_http_client_driver_add(const char *name_str, uint name_len, php_http_client_driver_t *driver) +{ + return zend_hash_add(&php_http_client_drivers, name_str, name_len + 1, (void *) driver, sizeof(php_http_client_driver_t), NULL); +} + +PHP_HTTP_API STATUS php_http_client_driver_get(char **name_str, uint *name_len, php_http_client_driver_t *driver) +{ + php_http_client_driver_t *tmp; + + if (*name_str && SUCCESS == zend_hash_find(&php_http_client_drivers, *name_str, (*name_len) + 1, (void *) &tmp)) { + *driver = *tmp; + return SUCCESS; + } else if (SUCCESS == zend_hash_get_current_data(&php_http_client_drivers, (void *) &tmp)) { + zend_hash_get_current_key_ex(&php_http_client_drivers, name_str, name_len, NULL, 0, NULL); + --(*name_len); + *driver = *tmp; + return SUCCESS; + } + return FAILURE; +} + +void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC) +{ + if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) { + zend_class_entry *this_ce = Z_OBJCE_P(getThis()); + zval *old_opts, *new_opts, **entry = NULL; + + MAKE_STD_ZVAL(new_opts); + array_init(new_opts); + old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + if (Z_TYPE_P(old_opts) == IS_ARRAY) { + array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); + } + + if (overwrite) { + if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { + Z_ADDREF_P(opts); + zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL); + } else { + zend_symtable_del(Z_ARRVAL_P(new_opts), key, len); + } + } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) { + array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, 0); + } else { + Z_ADDREF_P(opts); + zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL); + } + } + + zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); + zval_ptr_dtor(&new_opts); + } +} + +void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC) +{ + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + HashPosition pos; + zval *new_opts; + zend_class_entry *this_ce = Z_OBJCE_P(getThis()); + zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry TSRMLS_CC); + + MAKE_STD_ZVAL(new_opts); + array_init(new_opts); + + if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) { + zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); + zval_ptr_dtor(&new_opts); + } else { + zval *old_opts, *add_opts, **opt; + + MAKE_STD_ZVAL(add_opts); + array_init(add_opts); + /* some options need extra attention -- thus cannot use array_merge() directly */ + FOREACH_KEYVAL(pos, opts, key, opt) { + if (key.type == HASH_KEY_IS_STRING) { +#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s)) + if (Z_TYPE_PP(opt) == IS_ARRAY && (KEYMATCH(key, "ssl") || KEYMATCH(key, "cookies"))) { + php_http_client_options_set_subr(getThis(), key.str, key.len, *opt, 0 TSRMLS_CC); + } else if (is_client && (KEYMATCH(key, "recordHistory") || KEYMATCH(key, "responseMessageClass"))) { + zend_update_property(this_ce, getThis(), key.str, key.len-1, *opt TSRMLS_CC); + } else if (Z_TYPE_PP(opt) == IS_NULL) { + old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + if (Z_TYPE_P(old_opts) == IS_ARRAY) { + zend_symtable_del(Z_ARRVAL_P(old_opts), key.str, key.len); + } + } else { + Z_ADDREF_P(*opt); + add_assoc_zval_ex(add_opts, key.str, key.len, *opt); + } + } + } + + old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + if (Z_TYPE_P(old_opts) == IS_ARRAY) { + array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); + } + array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0); + zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); + zval_ptr_dtor(&new_opts); + zval_ptr_dtor(&add_opts); + } +} + +void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC) +{ + zend_class_entry *this_ce = Z_OBJCE_P(getThis()); + zval **options, *opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + + if ((Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) { + RETVAL_ZVAL(*options, 1, 0); + } +} + +static void queue_dtor(void *enqueued) +{ + php_http_client_enqueue_t *e = enqueued; + + if (e->dtor) { + e->dtor(e); + } +} PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC) { @@ -30,22 +147,15 @@ PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_h } else if (ops->rsrc) { h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL); } - h->request.buffer = php_http_buffer_init(NULL); - h->request.parser = php_http_message_parser_init(NULL TSRMLS_CC); - h->request.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); - - h->response.buffer = php_http_buffer_init(NULL); - h->response.parser = php_http_message_parser_init(NULL TSRMLS_CC); - h->response.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); - + zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0); + zend_llist_init(&h->responses, sizeof(void *), NULL, 0); TSRMLS_SET_CTX(h->ts); if (h->ops->init) { if (!(h = h->ops->init(h, init_arg))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Could not initialize request"); + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Could not initialize client"); if (free_h) { - h->ops->dtor = NULL; - php_http_client_free(&free_h); + efree(h); } } } @@ -53,25 +163,28 @@ PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_h return h; } +PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to) +{ + if (from->ops->copy) { + return from->ops->copy(from, to); + } + + return NULL; +} + PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h) { if (h->ops->dtor) { h->ops->dtor(h); } - php_resource_factory_free(&h->rf); + zend_llist_clean(&h->requests); + zend_llist_clean(&h->responses); - php_http_message_parser_free(&h->request.parser); - php_http_message_free(&h->request.message); - php_http_buffer_free(&h->request.buffer); - - php_http_message_parser_free(&h->response.parser); - php_http_message_free(&h->response.message); - php_http_buffer_free(&h->response.buffer); + php_resource_factory_free(&h->rf); } -PHP_HTTP_API void php_http_client_free(php_http_client_t **h) -{ +PHP_HTTP_API void php_http_client_free(php_http_client_t **h) { if (*h) { php_http_client_dtor(*h); efree(*h); @@ -79,53 +192,92 @@ PHP_HTTP_API void php_http_client_free(php_http_client_t **h) } } -PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to) +PHP_HTTP_API STATUS php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) { - if (!from->ops->copy) { - return NULL; - } else { - TSRMLS_FETCH_FROM_CTX(from->ts); + TSRMLS_FETCH_FROM_CTX(h->ts); - if (!to) { - to = ecalloc(1, sizeof(*to)); + if (h->ops->enqueue) { + if (php_http_client_enqueued(h, enqueue->request, NULL)) { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to enqueue request; request already in queue"); + return FAILURE; } + return h->ops->enqueue(h, enqueue); + } + + return FAILURE; +} + +PHP_HTTP_API STATUS php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request) +{ + TSRMLS_FETCH_FROM_CTX(h->ts); - to->ops = from->ops; - if (from->rf) { - php_resource_factory_addref(from->rf); - to->rf = from->rf; - } else if (to->ops->rsrc){ - to->rf = php_resource_factory_init(NULL, to->ops->rsrc, to, NULL); + if (h->ops->dequeue) { + php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL); + + if (!enqueue) { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to dequeue request; request not in queue"); + return FAILURE; } + return h->ops->dequeue(h, enqueue); + } + return FAILURE; +} - to->request.buffer = php_http_buffer_init(NULL); - to->request.parser = php_http_message_parser_init(NULL TSRMLS_CC); - to->request.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); +PHP_HTTP_API php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func) +{ + zend_llist_element *el = NULL; - to->response.buffer = php_http_buffer_init(NULL); - to->response.parser = php_http_message_parser_init(NULL TSRMLS_CC); - to->response.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + if (compare_func) { + for (el = h->requests.head; el; el = el->next) { + if (compare_func((php_http_client_enqueue_t *) el->data, compare_arg)) { + break; + } + } + } else { + for (el = h->requests.head; el; el = el->next) { + if (((php_http_client_enqueue_t *) el->data)->request == compare_arg) { + break; + } + } + } + return el ? (php_http_client_enqueue_t *) el->data : NULL; +} + +PHP_HTTP_API STATUS php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout) +{ + if (h->ops->wait) { + return h->ops->wait(h, custom_timeout); + } - TSRMLS_SET_CTX(to->ts); + return FAILURE; +} - return to->ops->copy(from, to); +PHP_HTTP_API int php_http_client_once(php_http_client_t *h) +{ + if (h->ops->once) { + return h->ops->once(h); } + + return FAILURE; } -PHP_HTTP_API STATUS php_http_client_exec(php_http_client_t *h, php_http_message_t *msg) +PHP_HTTP_API STATUS php_http_client_exec(php_http_client_t *h) { if (h->ops->exec) { - return h->ops->exec(h, msg); + return h->ops->exec(h); } + return FAILURE; } -PHP_HTTP_API STATUS php_http_client_reset(php_http_client_t *h) +PHP_HTTP_API void php_http_client_reset(php_http_client_t *h) { if (h->ops->reset) { - return h->ops->reset(h); + h->ops->reset(h); } - return FAILURE; + + zend_llist_clean(&h->requests); + zend_llist_clean(&h->responses); } PHP_HTTP_API STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) @@ -133,884 +285,779 @@ PHP_HTTP_API STATUS php_http_client_setopt(php_http_client_t *h, php_http_client if (h->ops->setopt) { return h->ops->setopt(h, opt, arg); } + return FAILURE; } -PHP_HTTP_API STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg) +PHP_HTTP_API STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr) { if (h->ops->getopt) { - return h->ops->getopt(h, opt, arg); + return h->ops->getopt(h, opt, arg, res_ptr); } return FAILURE; } -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClient, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClient, method, 0) -#define PHP_HTTP_CLIENT_ME(method, visibility) PHP_ME(HttpClient, method, PHP_HTTP_ARGS(HttpClient, method), visibility) -#define PHP_HTTP_CLIENT_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClient, method)) -#define PHP_HTTP_CLIENT_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClient_##al), PHP_HTTP_ARGS(HttpClient, al), vis) - -PHP_HTTP_BEGIN_ARGS(__construct, 0) - PHP_HTTP_ARG_ARR(options, 1, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(getOptions); -PHP_HTTP_BEGIN_ARGS(setOptions, 0) - PHP_HTTP_ARG_ARR(options, 1, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(getSslOptions); -PHP_HTTP_BEGIN_ARGS(setSslOptions, 0) - PHP_HTTP_ARG_ARR(ssl_options, 1, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_BEGIN_ARGS(addSslOptions, 0) - PHP_HTTP_ARG_ARR(ssl_options, 1, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(getCookies); -PHP_HTTP_BEGIN_ARGS(setCookies, 0) - PHP_HTTP_ARG_VAL(cookies, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_BEGIN_ARGS(addCookies, 1) - PHP_HTTP_ARG_VAL(cookies, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(enableCookies); -PHP_HTTP_BEGIN_ARGS(resetCookies, 0) - PHP_HTTP_ARG_VAL(session_only, 0) -PHP_HTTP_END_ARGS; -PHP_HTTP_EMPTY_ARGS(flushCookies); - -PHP_HTTP_EMPTY_ARGS(getResponseMessageClass); -PHP_HTTP_BEGIN_ARGS(setResponseMessageClass, 1) - PHP_HTTP_ARG_VAL(message_class_name, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(getResponseMessage); -PHP_HTTP_EMPTY_ARGS(getRequestMessage); -PHP_HTTP_EMPTY_ARGS(getHistory); -PHP_HTTP_EMPTY_ARGS(clearHistory); - -PHP_HTTP_BEGIN_ARGS(setRequest, 1) - PHP_HTTP_ARG_OBJ(http\\Client\\Request, request, 1) -PHP_HTTP_END_ARGS; -PHP_HTTP_EMPTY_ARGS(getRequest); - -PHP_HTTP_EMPTY_ARGS(getObservers); -PHP_HTTP_BEGIN_ARGS(attach, 1) - PHP_HTTP_ARG_OBJ(SplObserver, observer, 0) -PHP_HTTP_END_ARGS; -PHP_HTTP_BEGIN_ARGS(detach, 1) - PHP_HTTP_ARG_OBJ(SplObserver, observer, 0) -PHP_HTTP_END_ARGS; -PHP_HTTP_EMPTY_ARGS(notify); -PHP_HTTP_EMPTY_ARGS(getProgress); -PHP_HTTP_BEGIN_ARGS(getTransferInfo, 0) - PHP_HTTP_ARG_VAL(name, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_BEGIN_ARGS(request, 2) - PHP_HTTP_ARG_VAL(method, 0) - PHP_HTTP_ARG_VAL(url, 0) - PHP_HTTP_ARG_ARR(headers, 1, 0) - PHP_HTTP_ARG_VAL(body, 0) - PHP_HTTP_ARG_ARR(options, 1, 0) -PHP_HTTP_END_ARGS; - -static zend_class_entry *php_http_client_class_entry; - -zend_class_entry *php_http_client_get_class_entry(void) -{ - return php_http_client_class_entry; -} - -static zend_function_entry php_http_client_method_entry[] = { - PHP_HTTP_CLIENT_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - PHP_HTTP_CLIENT_ME(getObservers, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(notify, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(attach, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(detach, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getProgress, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getTransferInfo, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(setOptions, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getOptions, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(setSslOptions, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getSslOptions, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(addSslOptions, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(addCookies, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getCookies, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(setCookies, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(enableCookies, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(resetCookies, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(flushCookies, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(setRequest, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getRequest, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(getResponseMessage, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getRequestMessage, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(getHistory, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(clearHistory, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(getResponseMessageClass, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_ME(setResponseMessageClass, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_ME(request, ZEND_ACC_PUBLIC) - - EMPTY_FUNCTION_ENTRY -}; - +zend_class_entry *php_http_client_class_entry; static zend_object_handlers php_http_client_object_handlers; -zend_object_handlers *php_http_client_get_object_handlers(void) +void php_http_client_object_free(void *object TSRMLS_DC) { - return &php_http_client_object_handlers; -} - -static php_http_client_ops_t php_http_client_user_ops = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - (php_http_new_t) php_http_client_object_new_ex, - php_http_client_get_class_entry -}; + php_http_client_object_t *o = (php_http_client_object_t *) object; -zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC); + php_http_client_free(&o->client); + zend_object_std_dtor((zend_object *) o TSRMLS_CC); + efree(o); } -zend_object_value php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *r, php_http_client_object_t **ptr TSRMLS_DC) +zend_object_value php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client, php_http_client_object_t **ptr TSRMLS_DC) { - zend_object_value ov; php_http_client_object_t *o; - o = ecalloc(1, sizeof(*o)); + o = ecalloc(1, sizeof(php_http_client_object_t)); zend_object_std_init((zend_object *) o, ce TSRMLS_CC); object_properties_init((zend_object *) o, ce); - - ov.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC); - ov.handlers = &php_http_client_object_handlers; - if (!(o->client = r)) { - o->client = php_http_client_init(NULL, &php_http_client_user_ops, NULL, &ov TSRMLS_CC); - } + o->client = client; if (ptr) { *ptr = o; } - return ov; -} - -zend_object_value php_http_client_object_clone(zval *this_ptr TSRMLS_DC) -{ - zend_object_value new_ov; - php_http_client_object_t *new_obj, *old_obj = zend_object_store_get_object(this_ptr TSRMLS_CC); - - new_ov = php_http_client_object_new_ex(old_obj->zo.ce, php_http_client_copy(old_obj->client, NULL), &new_obj TSRMLS_CC); - zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); + o->zv.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_client_object_handlers; - return new_ov; -} - -void php_http_client_object_free(void *object TSRMLS_DC) -{ - php_http_client_object_t *o = (php_http_client_object_t *) object; - - php_http_client_free(&o->client); - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(o); + return o->zv; } -static inline zend_object_value php_http_client_object_message(zval *this_ptr, php_http_message_t *msg TSRMLS_DC) +zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC) { - zend_object_value ov; - zval *zcn = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("responseMessageClass"), 0 TSRMLS_CC); - zend_class_entry *class_entry; - - if (Z_STRLEN_P(zcn) - && (class_entry = zend_fetch_class(Z_STRVAL_P(zcn), Z_STRLEN_P(zcn), 0 TSRMLS_CC)) - && (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_object_new_ex, php_http_client_response_get_class_entry(), msg, NULL TSRMLS_CC))) { - return ov; - } else { - return php_http_message_object_new_ex(php_http_client_response_get_class_entry(), msg, NULL TSRMLS_CC); - } + return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC); } -STATUS php_http_client_object_handle_request(zval *zclient, zval **zreq TSRMLS_DC) +static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response TSRMLS_DC) { - php_http_client_object_t *obj = zend_object_store_get_object(zclient TSRMLS_CC); - php_http_client_progress_t *progress; - zval *zoptions; - HashTable options; + zval *new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0 TSRMLS_CC); + php_http_message_t *zipped = php_http_message_zip(response, request); + zend_object_value ov = php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped, NULL TSRMLS_CC); - /* do we have a valid request? */ - if (*zreq) { - /* remember the request */ - zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("request"), *zreq TSRMLS_CC); - } else { - /* maybe a request is already set */ - *zreq = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("request"), 0 TSRMLS_CC); - - if (Z_TYPE_PP(zreq) != IS_OBJECT || !instanceof_function(Z_OBJCE_PP(zreq), php_http_client_request_get_class_entry() TSRMLS_CC)) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "The client does not have a valid request set"); - return FAILURE; - } - } + MAKE_STD_ZVAL(new_hist); + ZVAL_OBJVAL(new_hist, ov, 0); - /* reset request handle */ - php_http_client_reset(obj->client); - - /* reset transfer info */ - zend_update_property_null(php_http_client_class_entry, zclient, ZEND_STRL("transferInfo") TSRMLS_CC); - - - /* set client options */ - zend_hash_init(&options, 0, NULL, ZVAL_PTR_DTOR, 0); - zoptions = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("options"), 0 TSRMLS_CC); - if (Z_TYPE_P(zoptions) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(zoptions))) { - php_array_merge(&options, Z_ARRVAL_P(zoptions), 1 TSRMLS_CC); - } - zoptions = zend_read_property(php_http_client_request_get_class_entry(), *zreq, ZEND_STRL("options"), 0 TSRMLS_CC); - if (Z_TYPE_P(zoptions) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(zoptions))) { - php_array_merge(&options, Z_ARRVAL_P(zoptions), 1 TSRMLS_CC); - } - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_SETTINGS, &options); - zend_hash_destroy(&options); - - /* set progress callback */ - if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, &progress)) { - if (!progress->callback) { - php_http_client_progress_callback_t *callback = emalloc(sizeof(*callback)); - - callback->type = PHP_HTTP_CLIENT_PROGRESS_CALLBACK_USER; - MAKE_STD_ZVAL(callback->func.user); - array_init(callback->func.user); - Z_ADDREF_P(zclient); - add_next_index_zval(callback->func.user, zclient); - add_next_index_stringl(callback->func.user, ZEND_STRL("notify"), 1); - - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK, callback); - } - progress->state.info = "start"; - php_http_client_progress_notify(progress TSRMLS_CC); - progress->state.started = 1; + if (Z_TYPE_P(old_hist) == IS_OBJECT) { + php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC); } - return SUCCESS; + zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC); + zval_ptr_dtor(&new_hist); } - -STATUS php_http_client_object_handle_response(zval *zclient TSRMLS_DC) +static STATUS handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response) { - php_http_client_object_t *obj = zend_object_store_get_object(zclient TSRMLS_CC); - php_http_client_progress_t *progress; + zval zclient; php_http_message_t *msg; - zval *info; - - /* always fetch info */ - MAKE_STD_ZVAL(info); - array_init(info); - php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, Z_ARRVAL_P(info)); - zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("transferInfo"), info TSRMLS_CC); - zval_ptr_dtor(&info); - - if ((msg = obj->client->response.message)) { - if (i_zend_is_true(zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) { - zval *new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0 TSRMLS_CC); - php_http_message_t *zipped = php_http_message_zip(obj->client->response.message, obj->client->request.message); - zend_object_value ov = php_http_client_object_message(zclient, zipped TSRMLS_CC); - - MAKE_STD_ZVAL(new_hist); - ZVAL_OBJVAL(new_hist, ov, 0); - - if (Z_TYPE_P(old_hist) == IS_OBJECT) { - php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC); - } - - zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC); - zval_ptr_dtor(&new_hist); - } + php_http_client_progress_state_t *progress; + TSRMLS_FETCH_FROM_CTX(client->ts); - /* update response info */ - if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, msg)) { - zval *message; + INIT_PZVAL(&zclient); + ZVAL_OBJVAL(&zclient, ((php_http_client_object_t*) arg)->zv, 0); - MAKE_STD_ZVAL(message); - ZVAL_OBJVAL(message, php_http_client_object_message(zclient, msg TSRMLS_CC), 0); - zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("responseMessage"), message TSRMLS_CC); - zval_ptr_dtor(&message); + if ((msg = *response)) { + php_http_message_object_t *msg_obj; + zval *info, *zresponse, *zrequest; - obj->client->response.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); - } else { - zend_update_property_null(php_http_client_class_entry, zclient, ZEND_STRL("responseMessage") TSRMLS_CC); + if (i_zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) { + handle_history(&zclient, *request, *response TSRMLS_CC); } - } else { - zend_update_property_null(php_http_client_class_entry, zclient, ZEND_STRL("responseMessage") TSRMLS_CC); - } - if ((msg = obj->client->request.message)) { - if (PHP_HTTP_MESSAGE_TYPE(REQUEST, msg)) { - zval *message; + /* hard detach, redirects etc. are in the history */ + php_http_message_free(&msg->parent); + *response = NULL; - /* update the actual request message */ - MAKE_STD_ZVAL(message); - ZVAL_OBJVAL(message, php_http_message_object_new_ex(php_http_message_get_class_entry(), msg, NULL TSRMLS_CC), 0); - zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("requestMessage"), message TSRMLS_CC); - zval_ptr_dtor(&message); - obj->client->request.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); - } - } + MAKE_STD_ZVAL(zresponse); + ZVAL_OBJVAL(zresponse, php_http_message_object_new_ex(php_http_client_response_get_class_entry(), msg, &msg_obj TSRMLS_CC), 0); - if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, &progress)) { - progress->state.info = "finished"; - progress->state.finished = 1; - php_http_client_progress_notify(progress TSRMLS_CC); - } - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK, NULL); + MAKE_STD_ZVAL(zrequest); + ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1); - return SUCCESS; -} + php_http_message_object_prepend(zresponse, zrequest, 1 TSRMLS_CC); -void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC) -{ - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - HashPosition pos; - zval *new_opts; - zend_class_entry *this_ce = Z_OBJCE_P(getThis()); - zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry TSRMLS_CC); + MAKE_STD_ZVAL(info); + array_init(info); + php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &Z_ARRVAL_P(info)); + zend_update_property(php_http_client_response_get_class_entry(), zresponse, ZEND_STRL("transferInfo"), info TSRMLS_CC); + zval_ptr_dtor(&info); - MAKE_STD_ZVAL(new_opts); - array_init(new_opts); + zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC); + zend_llist_add_element(&client->responses, &msg_obj); - if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) { - zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); - zval_ptr_dtor(&new_opts); - } else { - zval *old_opts, *add_opts, **opt; + if (e->closure.fci.size) { + zval *retval = NULL; - MAKE_STD_ZVAL(add_opts); - array_init(add_opts); - /* some options need extra attention -- thus cannot use array_merge() directly */ - FOREACH_KEYVAL(pos, opts, key, opt) { - if (key.type == HASH_KEY_IS_STRING) { -#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s)) - if (Z_TYPE_PP(opt) == IS_ARRAY && (KEYMATCH(key, "ssl") || KEYMATCH(key, "cookies"))) { - php_http_client_options_set_subr(getThis(), key.str, key.len, *opt, 0 TSRMLS_CC); - } else if (is_client && (KEYMATCH(key, "recordHistory") || KEYMATCH(key, "responseMessageClass"))) { - zend_update_property(this_ce, getThis(), key.str, key.len-1, *opt TSRMLS_CC); - } else if (Z_TYPE_PP(opt) == IS_NULL) { - old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); - if (Z_TYPE_P(old_opts) == IS_ARRAY) { - zend_symtable_del(Z_ARRVAL_P(old_opts), key.str, key.len); - } - } else { - Z_ADDREF_P(*opt); - add_assoc_zval_ex(add_opts, key.str, key.len, *opt); + zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 1, &zresponse); + with_error_handling(EH_NORMAL, NULL) { + zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL TSRMLS_CC); + } end_error_handling(); + zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 0); + + if (retval) { + if (Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)) { + php_http_client_dequeue(client, e->request); } + zval_ptr_dtor(&retval); } } - old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); - if (Z_TYPE_P(old_opts) == IS_ARRAY) { - array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); - } - array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0); - zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); - zval_ptr_dtor(&new_opts); - zval_ptr_dtor(&add_opts); + zval_ptr_dtor(&zresponse); + zval_ptr_dtor(&zrequest); } -} - -void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC) -{ - if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) { - zend_class_entry *this_ce = Z_OBJCE_P(getThis()); - zval *old_opts, *new_opts, **entry = NULL; - - MAKE_STD_ZVAL(new_opts); - array_init(new_opts); - old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); - if (Z_TYPE_P(old_opts) == IS_ARRAY) { - array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); - } - - if (overwrite) { - if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { - Z_ADDREF_P(opts); - zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL); - } else { - zend_symtable_del(Z_ARRVAL_P(new_opts), key, len); - } - } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { - if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) { - array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, 0); - } else { - Z_ADDREF_P(opts); - zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL); - } - } - zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC); - zval_ptr_dtor(&new_opts); + if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) { + progress->info = "finished"; + progress->finished = 1; + client->callback.progress.func(client->callback.progress.arg, client, e, progress); } + + return SUCCESS; } -void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC) +static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state) { - zend_class_entry *this_ce = Z_OBJCE_P(getThis()); - zval **options, *opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); - - if ((Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) { - RETVAL_ZVAL(*options, 1, 0); + zval *zrequest, *retval = NULL, *zclient; + TSRMLS_FETCH_FROM_CTX(client->ts); + + MAKE_STD_ZVAL(zclient); + ZVAL_OBJVAL(zclient, ((php_http_client_object_t *) arg)->zv, 1); + MAKE_STD_ZVAL(zrequest); + ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1); + with_error_handling(EH_NORMAL, NULL) { + zend_call_method_with_1_params(&zclient, NULL, NULL, "notify", &retval, zrequest); + } end_error_handling(); + zval_ptr_dtor(&zclient); + zval_ptr_dtor(&zrequest); + if (retval) { + zval_ptr_dtor(&retval); } } -PHP_METHOD(HttpClient, __construct) +static void response_dtor(void *data) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - zval *os, *opts = NULL; - - MAKE_STD_ZVAL(os); - object_init_ex(os, spl_ce_SplObjectStorage); - zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC); - zval_ptr_dtor(&os); - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set(getThis(), opts TSRMLS_CC); - } + php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data; + TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts); - } end_error_handling(); + zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC); } -PHP_METHOD(HttpClient, getObservers) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0) + ZEND_ARG_INFO(0, driver) + ZEND_ARG_INFO(0, persistent_handle_id) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, __construct) { with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters_none()) { - RETVAL_PROP(php_http_client_class_entry, "observers"); + char *driver_str = NULL, *persistent_handle_str = NULL; + int driver_len = 0, persistent_handle_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &driver_str, &driver_len, &persistent_handle_str, &persistent_handle_len)) { + php_http_client_driver_t driver; + + if (SUCCESS == php_http_client_driver_get(&driver_str, (uint *) &driver_len, &driver)) { + php_resource_factory_t *rf = NULL; + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *os; + + MAKE_STD_ZVAL(os); + object_init_ex(os, spl_ce_SplObjectStorage); + zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC); + zval_ptr_dtor(&os); + + if (persistent_handle_len) { + char *name_str; + size_t name_len; + php_persistent_handle_factory_t *pf; + + name_len = spprintf(&name_str, 0, "http\\Client\\%s", php_http_pretty_key(driver_str, driver_len, 1, 1)); + + if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, persistent_handle_str, persistent_handle_len, NULL, NULL TSRMLS_CC))) { + rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon); + } + + efree(name_str); + } + + if ((obj->client = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC))) { + obj->client->callback.response.func = handle_response; + obj->client->callback.response.arg = obj; + obj->client->callback.progress.func = handle_progress; + obj->client->callback.progress.arg = obj; + + obj->client->responses.dtor = response_dtor; + } + } else { + php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "Failed to locate \"%s\" client request handler", driver_str); + } } } end_error_handling(); } -static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, reset) { - zval **observer = NULL; - - iter->funcs->get_current_data(iter, &observer TSRMLS_CC); - if (observer) { - zval *retval; + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - zend_call_method_with_1_params(observer, NULL, NULL, "update", &retval, puser); - zval_ptr_dtor(&retval); - return SUCCESS; + obj->iterator = 0; + php_http_client_reset(obj->client); } - return FAILURE; + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, notify) +static HashTable *combined_options(zval *client, zval *request TSRMLS_DC) { - if (SUCCESS == zend_parse_parameters_none()) { - zval *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + HashTable *options; + int num_options = 0; + zval *z_roptions = NULL, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0 TSRMLS_CC); - if (Z_TYPE_P(observers) == IS_OBJECT) { - Z_ADDREF_P(getThis()); - spl_iterator_apply(observers, notify, getThis() TSRMLS_CC); - zval_ptr_dtor(&getThis()); + if (Z_TYPE_P(z_coptions) == IS_ARRAY) { + num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions)); + } + zend_call_method_with_0_params(&request, NULL, NULL, "getOptions", &z_roptions); + if (z_roptions && Z_TYPE_P(z_roptions) == IS_ARRAY) { + int num = zend_hash_num_elements(Z_ARRVAL_P(z_roptions)); + if (num > num_options) { + num_options = num; } } - - RETVAL_ZVAL(getThis(), 1, 0); + ALLOC_HASHTABLE(options); + ZEND_INIT_SYMTABLE_EX(options, num_options, 0); + if (Z_TYPE_P(z_coptions) == IS_ARRAY) { + array_copy(Z_ARRVAL_P(z_coptions), options); + } + if (z_roptions) { + if (Z_TYPE_P(z_roptions) == IS_ARRAY) { + array_join(Z_ARRVAL_P(z_roptions), options, 1, 0); + } + zval_ptr_dtor(&z_roptions); + } + return options; } -PHP_METHOD(HttpClient, attach) +static void msg_queue_dtor(php_http_client_enqueue_t *e) { - zval *observer; + php_http_message_object_t *msg_obj = e->opaque; + TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver)) { - zval *retval, *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); - zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer); - zval_ptr_dtor(&retval); - } + zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC); + zend_hash_destroy(e->options); + FREE_HASHTABLE(e->options); - RETVAL_ZVAL(getThis(), 1, 0); + if (e->closure.fci.size) { + zval_ptr_dtor(&e->closure.fci.function_name); + if (e->closure.fci.object_ptr) { + zval_ptr_dtor(&e->closure.fci.object_ptr); + } + } } -PHP_METHOD(HttpClient, detach) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) + ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, enqueue) { - zval *observer; + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { + zval *request; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver)) { - zval *retval, *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); - zend_call_method_with_1_params(&observers, NULL, NULL, "detach", &retval, observer); - zval_ptr_dtor(&retval); - } + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|f", &request, php_http_client_request_get_class_entry(), &fci, &fcc)) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_object_t *msg_obj = zend_object_store_get_object(request TSRMLS_CC); + + if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to enqueue request; request already in queue"); + } else { + php_http_client_enqueue_t q = { + msg_obj->message, + combined_options(getThis(), request TSRMLS_CC), + msg_queue_dtor, + msg_obj, + {fci, fcc} + }; + + if (fci.size) { + Z_ADDREF_P(fci.function_name); + if (fci.object_ptr) { + Z_ADDREF_P(fci.object_ptr); + } + } + + zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC); + php_http_client_enqueue(obj->client, &q); + } + } + } end_error_handling(); RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, getProgress) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, dequeue) { - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - php_http_client_progress_t *progress = NULL; - - if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, &progress)) { - object_init(return_value); - add_property_bool(return_value, "started", progress->state.started); - add_property_bool(return_value, "finished", progress->state.finished); - add_property_string(return_value, "info", STR_PTR(progress->state.info), 1); - add_property_double(return_value, "dltotal", progress->state.dl.total); - add_property_double(return_value, "dlnow", progress->state.dl.now); - add_property_double(return_value, "ultotal", progress->state.ul.total); - add_property_double(return_value, "ulnow", progress->state.ul.now); + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { + zval *request; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_get_class_entry())) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_object_t *msg_obj = zend_object_store_get_object(request TSRMLS_CC); + + php_http_client_dequeue(obj->client, msg_obj->message); } - } + } end_error_handling(); + + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, getTransferInfo) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) + ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, requeue) { - char *info_name = NULL; - int info_len = 0; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) { - zval **infop, *temp = NULL, *info = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("transferInfo"), 0 TSRMLS_CC); + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { + zval *request; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; - /* request completed? */ - if (Z_TYPE_P(info) != IS_ARRAY) { + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|f", &request, php_http_client_request_get_class_entry(), &fci, &fcc)) { php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_object_t *msg_obj = zend_object_store_get_object(request TSRMLS_CC); + php_http_client_enqueue_t q = { + msg_obj->message, + combined_options(getThis(), request TSRMLS_CC), + msg_queue_dtor, + msg_obj, + {fci, fcc} + }; + + if (fci.size) { + Z_ADDREF_P(fci.function_name); + if (fci.object_ptr) { + Z_ADDREF_P(fci.object_ptr); + } + } - MAKE_STD_ZVAL(temp); - array_init(temp); - php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, Z_ARRVAL_P(temp)); - info = temp; - } - - if (info_len && info_name) { - if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(info), php_http_pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) { - RETVAL_ZVAL(*infop, 1, 0); - } else { - php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Could not find transfer info named %s", info_name); - RETVAL_FALSE; + zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC); + if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) { + php_http_client_dequeue(obj->client, msg_obj->message); } - } else { - RETVAL_ZVAL(info, 1, 0); + php_http_client_enqueue(obj->client, &q); } + } end_error_handling(); - if (temp) { - zval_ptr_dtor(&temp); - } - return; - } - RETURN_FALSE; + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, setOptions) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getResponse) { - zval *opts = NULL; + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set(getThis(), opts TSRMLS_CC); + if (obj->client->responses.tail) { + php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data; - RETVAL_ZVAL(getThis(), 1, 0); + /* pop off and go */ + if (response_obj) { + RETVAL_OBJVAL(response_obj->zv, 1); + zend_llist_remove_tail(&obj->client->responses); + } + } } } -PHP_METHOD(HttpClient, getOptions) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getHistory) { if (SUCCESS == zend_parse_parameters_none()) { - RETURN_PROP(php_http_client_class_entry, "options"); + zval *zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC); + RETVAL_ZVAL(zhistory, 1, 0); } - RETURN_FALSE; } -PHP_METHOD(HttpClient, setSslOptions) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, send) { - zval *opts = NULL; + RETVAL_FALSE; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC); + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { + if (SUCCESS == zend_parse_parameters_none()) { + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - RETVAL_ZVAL(getThis(), 1, 0); - } + php_http_client_exec(obj->client); + } end_error_handling(); + } + } end_error_handling(); + + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, addSslOptions) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, once) { - zval *opts = NULL; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC); + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - RETVAL_ZVAL(getThis(), 1, 0); + if (0 < php_http_client_once(obj->client)) { + RETURN_TRUE; + } } + RETURN_FALSE; } -PHP_METHOD(HttpClient, getSslOptions) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0) + ZEND_ARG_INFO(0, timeout) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, wait) { - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC); + double timeout = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) { + struct timeval timeout_val; + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + timeout_val.tv_sec = (time_t) timeout; + timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC; + + RETURN_SUCCESS(php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL)); } + RETURN_FALSE; } -PHP_METHOD(HttpClient, setCookies) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0) + ZEND_ARG_INFO(0, enable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, enablePipelining) { - zval *opts = NULL; + zend_bool enable = 1; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 1 TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - RETVAL_ZVAL(getThis(), 1, 0); + php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable); } + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, addCookies) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0) + ZEND_ARG_INFO(0, enable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, enableEvents) { - zval *opts = NULL; + zend_bool enable = 1; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { - php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - RETVAL_ZVAL(getThis(), 1, 0); + php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable); } + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, getCookies) +static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC) { - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC); + zval **observer = NULL, **args = puser; + + iter->funcs->get_current_data(iter, &observer TSRMLS_CC); + if (observer) { + zval *retval = NULL; + + zend_call_method(observer, NULL, NULL, ZEND_STRL("update"), &retval, args[1]?2:1, args[0], args[1] TSRMLS_CC); + if (retval) { + zval_ptr_dtor(&retval); + } + + return SUCCESS; } + return FAILURE; } -PHP_METHOD(HttpClient, enableCookies) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, notify) { - if (SUCCESS == zend_parse_parameters_none()){ - php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *request = NULL; - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE, NULL); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!", &request, php_http_client_request_get_class_entry())) { + zval *args[2], *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + + if (Z_TYPE_P(observers) == IS_OBJECT) { + Z_ADDREF_P(getThis()); + if (request) { + Z_ADDREF_P(request); + } + args[0] = getThis(); + args[1] = request; + spl_iterator_apply(observers, notify, &args TSRMLS_CC); + zval_ptr_dtor(&getThis()); + if (request) { + zval_ptr_dtor(&request); + } + } } + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, resetCookies) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, attach) { - zend_bool session_only = 0; + zval *observer; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &session_only)) { - php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (session_only) { - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION, NULL); - } else { - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_RESET, NULL); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver)) { + zval *retval = NULL, *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer); + if (retval) { + zval_ptr_dtor(&retval); } } + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, flushCookies) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, detach) { - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *observer; - php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH, NULL); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver)) { + zval *retval, *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + zend_call_method_with_1_params(&observers, NULL, NULL, "detach", &retval, observer); + zval_ptr_dtor(&retval); } + RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, getResponseMessage) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getObservers) { with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { if (SUCCESS == zend_parse_parameters_none()) { - zval *message = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC); - - if (Z_TYPE_P(message) == IS_OBJECT) { - RETVAL_OBJECT(message, 1); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpClient does not contain a response message"); - } + zval *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); + RETVAL_ZVAL(observers, 1, 0); } } end_error_handling(); } -PHP_METHOD(HttpClient, getRequestMessage) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getProgressInfo) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters_none()) { - zval *message = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("requestMessage"), 0 TSRMLS_CC); + zval *request; - if (Z_TYPE_P(message) == IS_OBJECT) { - RETVAL_OBJECT(message, 1); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpClient does not contain a request message"); + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_get_class_entry())) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_object_t *req_obj = zend_object_store_get_object(request TSRMLS_CC); + php_http_client_progress_state_t *progress; + + if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress)) { + object_init(return_value); + add_property_bool(return_value, "started", progress->started); + add_property_bool(return_value, "finished", progress->finished); + add_property_string(return_value, "info", STR_PTR(progress->info), 1); + add_property_double(return_value, "dltotal", progress->dl.total); + add_property_double(return_value, "dlnow", progress->dl.now); + add_property_double(return_value, "ultotal", progress->ul.total); + add_property_double(return_value, "ulnow", progress->ul.now); } } } end_error_handling(); } -PHP_METHOD(HttpClient, getHistory) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getTransferInfo) { + zval *request; + with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters_none()) { - zval *hist = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_get_class_entry())) { + php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_http_message_object_t *req_obj = zend_object_store_get_object(request TSRMLS_CC); - if (Z_TYPE_P(hist) == IS_OBJECT) { - RETVAL_OBJECT(hist, 1); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "The history is empty"); - } + array_init(return_value); + php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &Z_ARRVAL_P(return_value)); } } end_error_handling(); } -PHP_METHOD(HttpClient, clearHistory) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setOptions) { - if (SUCCESS == zend_parse_parameters_none()) { - zend_update_property_null(php_http_client_class_entry, getThis(), ZEND_STRL("history") TSRMLS_CC); + zval *opts = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { + php_http_client_options_set(getThis(), opts TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); } - RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, getResponseMessageClass) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getOptions) { if (SUCCESS == zend_parse_parameters_none()) { - RETURN_PROP(php_http_client_class_entry, "responseMessageClass"); + zval *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC); + RETVAL_ZVAL(options, 1, 0); } - RETURN_FALSE; } -PHP_METHOD(HttpClient, setResponseMessageClass) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, ssl_option, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setSslOptions) { - char *cn; - int cl; + zval *opts = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { + php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cn, &cl)) { - zend_update_property_stringl(php_http_client_class_entry, getThis(), ZEND_STRL("responseMessageClass"), cn, cl TSRMLS_CC); + RETVAL_ZVAL(getThis(), 1, 0); } - RETVAL_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, setRequest) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, ssl_options, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, addSslOptions) { - zval *zreq = NULL; + zval *opts = NULL; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zreq, php_http_client_request_get_class_entry())) { - zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("request"), zreq TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { + php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC); + + RETVAL_ZVAL(getThis(), 1, 0); } - RETURN_ZVAL(getThis(), 1, 0); } -PHP_METHOD(HttpClient, getRequest) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getSslOptions) { if (SUCCESS == zend_parse_parameters_none()) { - RETURN_PROP(php_http_client_class_entry, "request"); + php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC); } } -PHP_METHOD(HttpClient, request) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, cookies, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setCookies) { - char *meth_str, *url_str; - int meth_len, url_len; - zval *zheader, *zbody, *zoptions; - - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a!z!a!/", &meth_str, &meth_len, &url_str, &url_len, &zheader, &zbody, &zoptions)) { - php_http_message_object_t *msg_obj; - zend_object_value ov; - zval *req, *res = NULL; - - php_http_new(&ov, php_http_client_request_get_class_entry(), (php_http_new_t) php_http_message_object_new_ex, NULL, NULL, (void *) &msg_obj TSRMLS_CC); - MAKE_STD_ZVAL(req); - ZVAL_OBJVAL(req, ov, 0); - - msg_obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL TSRMLS_CC); - PHP_HTTP_INFO(msg_obj->message).request.url = estrndup(url_str, url_len); - PHP_HTTP_INFO(msg_obj->message).request.method = estrndup(meth_str, meth_len); - - if (zheader) { - array_copy(Z_ARRVAL_P(zheader), &msg_obj->message->hdrs); - } - - if (zbody) { - php_http_message_object_set_body(msg_obj, zbody TSRMLS_CC); - } + zval *opts = NULL; - if (zoptions) { - php_http_client_options_set(req, zoptions TSRMLS_CC); - } + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { + php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 1 TSRMLS_CC); - zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "send", &res, req); - RETVAL_ZVAL(res, 0, 1); - zval_ptr_dtor(&req); - } - } end_error_handling(); + RETVAL_ZVAL(getThis(), 1, 0); + } } -PHP_METHOD(HttpClient, send) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0) + ZEND_ARG_ARRAY_INFO(0, cookies, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, addCookies) { - zval *zreq = NULL; - - RETVAL_FALSE; + zval *opts = NULL; - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!", &zreq, php_http_client_request_get_class_entry())) { - if (SUCCESS == php_http_client_object_handle_request(getThis(), &zreq TSRMLS_CC)) { - php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - php_http_message_object_t *req = zend_object_store_get_object(zreq TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) { + php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC); - php_http_client_exec(obj->client, req->message); + RETVAL_ZVAL(getThis(), 1, 0); + } +} - if (SUCCESS == php_http_client_object_handle_response(getThis() TSRMLS_CC)) { - RETVAL_PROP(php_http_client_class_entry, "responseMessage"); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to handle response"); - } - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to handle request"); - } - } - } end_error_handling(); +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, getCookies) +{ + if (SUCCESS == zend_parse_parameters_none()) { + php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC); + } } +static zend_function_entry php_http_client_methods[] = { + PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, enqueue, ai_HttpClient_enqueue, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, dequeue, ai_HttpClient_dequeue, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, requeue, ai_HttpClient_requeue, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, send, ai_HttpClient_send, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, once, ai_HttpClient_once, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, wait, ai_HttpClient_wait, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getResponse, ai_HttpClient_getResponse, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getHistory, ai_HttpClient_getHistory, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, enablePipelining, ai_HttpClient_enablePipelining, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, enableEvents, ai_HttpClient_enableEvents, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, notify, ai_HttpClient_notify, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, attach, ai_HttpClient_attach, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, detach, ai_HttpClient_detach, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getObservers, ai_HttpClient_getObservers, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getProgressInfo, ai_HttpClient_getProgressInfo, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getTransferInfo, ai_HttpClient_getTransferInfo, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setOptions, ai_HttpClient_setOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getOptions, ai_HttpClient_getOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setSslOptions, ai_HttpClient_setSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, addSslOptions, ai_HttpClient_addSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getSslOptions, ai_HttpClient_getSslOptions, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setCookies, ai_HttpClient_setCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, addCookies, ai_HttpClient_addCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, getCookies, ai_HttpClient_getCookies, ZEND_ACC_PUBLIC) + EMPTY_FUNCTION_ENTRY +}; + PHP_MINIT_FUNCTION(http_client) { - PHP_HTTP_REGISTER_CLASS(http\\Client, AbstractClient, http_client, php_http_object_get_class_entry(), ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); + zend_class_entry ce = {0}; + + INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods); + php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); php_http_client_class_entry->create_object = php_http_client_object_new; + zend_class_implements(php_http_client_class_entry TSRMLS_CC, 1, spl_ce_SplSubject); memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - php_http_client_object_handlers.clone_obj = php_http_client_object_clone; - - zend_class_implements(php_http_client_class_entry TSRMLS_CC, 2, spl_ce_SplSubject, php_http_client_interface_get_class_entry()); - - zend_declare_property_string(php_http_client_class_entry, ZEND_STRL("responseMessageClass"), "", ZEND_ACC_PRIVATE TSRMLS_CC); + php_http_client_object_handlers.clone_obj = NULL; zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("transferInfo"), ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("responseMessage"), ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("requestMessage"), ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC); - zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("request"), ZEND_ACC_PROTECTED TSRMLS_CC); - + zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED TSRMLS_CC); zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_hash_init(&php_http_client_drivers, 2, NULL, NULL, 1); + return SUCCESS; } -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - +PHP_MSHUTDOWN_FUNCTION(http_client) +{ + zend_hash_destroy(&php_http_client_drivers); + return SUCCESS; +} diff --git a/php_http_client.h b/php_http_client.h index 3562af9..42b7131 100644 --- a/php_http_client.h +++ b/php_http_client.h @@ -1,110 +1,38 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - #ifndef PHP_HTTP_CLIENT_H #define PHP_HTTP_CLIENT_H -#include "php_http_message_body.h" -#include "php_http_message_parser.h" - -typedef struct php_http_client_progress_state { - struct { - double now; - double total; - } ul; - struct { - double now; - double total; - } dl; - const char *info; - unsigned started:1; - unsigned finished:1; -} php_http_client_progress_state_t; - -#define PHP_HTTP_CLIENT_PROGRESS_CALLBACK_USER 0 -#define PHP_HTTP_CLIENT_PROGRESS_CALLBACK_INTERN 1 -typedef struct php_http_client_progress_callback { - union { - zval *user; - void (*intern)(php_http_client_progress_state_t* TSRMLS_DC); - } func; - unsigned type:1; -} php_http_client_progress_callback_t; - -typedef struct php_http_client_progress { - php_http_client_progress_state_t state; - php_http_client_progress_callback_t *callback; - unsigned in_cb:1; -} php_http_client_progress_t; - -static inline void php_http_client_progress_dtor(php_http_client_progress_t *progress TSRMLS_DC) -{ - if (progress->callback) { - if (progress->callback->type == PHP_HTTP_CLIENT_PROGRESS_CALLBACK_USER) { - zval_ptr_dtor(&progress->callback->func.user); - } - efree(progress->callback); - } - memset(progress, 0, sizeof(*progress)); -} - -static inline void php_http_client_progress_notify(php_http_client_progress_t *progress TSRMLS_DC) -{ - if (progress->callback) { - zval retval; - - INIT_PZVAL(&retval); - ZVAL_NULL(&retval); - - with_error_handling(EH_NORMAL, NULL) { - switch (progress->callback->type) { - case PHP_HTTP_CLIENT_PROGRESS_CALLBACK_USER: - progress->in_cb = 1; - call_user_function(EG(function_table), NULL, progress->callback->func.user, &retval, 0, NULL TSRMLS_CC); - progress->in_cb = 0; - break; - case PHP_HTTP_CLIENT_PROGRESS_CALLBACK_INTERN: - progress->callback->func.intern(&progress->state TSRMLS_CC); - break; - default: - break; - } - } end_error_handling(); - - zval_dtor(&retval); - } -} - typedef enum php_http_client_setopt_opt { - PHP_HTTP_CLIENT_OPT_SETTINGS, /* HashTable* */ - PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK, /* php_http_client_progress_callback_t* */ - PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE, /* - */ - PHP_HTTP_CLIENT_OPT_COOKIES_RESET, /* - */ - PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION, /* - */ - PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH, /* - */ + PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, + PHP_HTTP_CLIENT_OPT_USE_EVENTS, } php_http_client_setopt_opt_t; typedef enum php_http_client_getopt_opt { - PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, /* php_http_client_progress_t** */ + PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, /* php_http_client_progress_state_t** */ PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, /* HashTable* */ } php_http_client_getopt_opt_t; -typedef struct php_http_client *(*php_http_client_init_func_t)(struct php_http_client *h, void *arg); +typedef struct php_http_client_enqueue { + php_http_message_t *request; /* unique */ + HashTable *options; + void (*dtor)(struct php_http_client_enqueue *); + void *opaque; + struct { + zend_fcall_info fci; + zend_fcall_info_cache fcc; + } closure; +} php_http_client_enqueue_t; + +typedef struct php_http_client *(*php_http_client_init_func_t)(struct php_http_client *p, void *init_arg); typedef struct php_http_client *(*php_http_client_copy_func_t)(struct php_http_client *from, struct php_http_client *to); -typedef void (*php_http_client_dtor_func_t)(struct php_http_client *h); -typedef STATUS (*php_http_client_exec_func_t)(struct php_http_client *h, php_http_message_t *msg); -typedef STATUS (*php_http_client_reset_func_t)(struct php_http_client *h); -typedef STATUS (*php_http_client_setopt_func_t)(struct php_http_client *h, php_http_client_setopt_opt_t opt, void *arg); -typedef STATUS (*php_http_client_getopt_func_t)(struct php_http_client *h, php_http_client_getopt_opt_t opt, void *arg); +typedef void (*php_http_client_dtor_func_t)(struct php_http_client *p); +typedef void (*php_http_client_reset_func_t)(struct php_http_client *p); +typedef STATUS (*php_http_client_exec_func_t)(struct php_http_client *p); +typedef int (*php_http_client_once_func_t)(struct php_http_client *p); +typedef STATUS (*php_http_client_wait_func_t)(struct php_http_client *p, struct timeval *custom_timeout); +typedef STATUS (*php_http_client_enqueue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); +typedef STATUS (*php_http_client_dequeue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue); +typedef STATUS (*php_http_client_setopt_func_t)(struct php_http_client *p, php_http_client_setopt_opt_t opt, void *arg); +typedef STATUS (*php_http_client_getopt_func_t)(struct php_http_client *h, php_http_client_getopt_opt_t opt, void *arg, void **res); typedef struct php_http_client_ops { php_resource_factory_ops_t *rsrc; @@ -113,99 +41,93 @@ typedef struct php_http_client_ops { php_http_client_dtor_func_t dtor; php_http_client_reset_func_t reset; php_http_client_exec_func_t exec; + php_http_client_wait_func_t wait; + php_http_client_once_func_t once; + php_http_client_enqueue_func_t enqueue; + php_http_client_dequeue_func_t dequeue; php_http_client_setopt_func_t setopt; php_http_client_getopt_func_t getopt; - php_http_new_t create_object; - zend_class_entry *(*class_entry)(void); } php_http_client_ops_t; +typedef struct php_http_client_driver { + php_http_client_ops_t *client_ops; +} php_http_client_driver_t; + +PHP_HTTP_API STATUS php_http_client_driver_add(const char *name_str, uint name_len, php_http_client_driver_t *driver); +PHP_HTTP_API STATUS php_http_client_driver_get(char **name_str, uint *name_len, php_http_client_driver_t *driver); + +typedef struct php_http_client_progress_state { + struct { + double now; + double total; + } ul; + struct { + double now; + double total; + } dl; + const char *info; + unsigned started:1; + unsigned finished:1; +} php_http_client_progress_state_t; + +typedef STATUS (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response); +typedef void (*php_http_client_progress_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state); + typedef struct php_http_client { void *ctx; php_resource_factory_t *rf; php_http_client_ops_t *ops; + struct { - php_http_message_parser_t *parser; - php_http_message_t *message; - php_http_buffer_t *buffer; - } request; - struct { - php_http_message_parser_t *parser; - php_http_message_t *message; - php_http_buffer_t *buffer; - } response; + struct { + php_http_client_response_callback_t func; + void *arg; + } response; + struct { + php_http_client_progress_callback_t func; + void *arg; + } progress; + } callback; + + zend_llist requests; + zend_llist responses; + #ifdef ZTS void ***ts; #endif } php_http_client_t; -PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); -PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to); -PHP_HTTP_API STATUS php_http_client_exec(php_http_client_t *h, php_http_message_t *msg); -PHP_HTTP_API STATUS php_http_client_reset(php_http_client_t *h); -PHP_HTTP_API STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg); -PHP_HTTP_API STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg); -PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h); -PHP_HTTP_API void php_http_client_free(php_http_client_t **h); +zend_class_entry *php_http_client_class_entry; typedef struct php_http_client_object { zend_object zo; + zend_object_value zv; php_http_client_t *client; + long iterator; } php_http_client_object_t; -zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *r, php_http_client_object_t **ptr TSRMLS_DC); -zend_object_value php_http_client_object_clone(zval *zobject TSRMLS_DC); -void php_http_client_object_free(void *object TSRMLS_DC); - -zend_class_entry *php_http_client_get_class_entry(void); -zend_object_handlers *php_http_client_get_object_handlers(void); - -STATUS php_http_client_object_handle_request(zval *zclient, zval **zreq TSRMLS_DC); -STATUS php_http_client_object_handle_response(zval *zclient TSRMLS_DC); - -void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC); -void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC); -void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC); - -PHP_METHOD(HttpClient, __construct); -PHP_METHOD(HttpClient, getObservers); -PHP_METHOD(HttpClient, notify); -PHP_METHOD(HttpClient, attach); -PHP_METHOD(HttpClient, detach); -PHP_METHOD(HttpClient, getProgress); -PHP_METHOD(HttpClient, getTransferInfo); -PHP_METHOD(HttpClient, setOptions); -PHP_METHOD(HttpClient, getOptions); -PHP_METHOD(HttpClient, addSslOptions); -PHP_METHOD(HttpClient, setSslOptions); -PHP_METHOD(HttpClient, getSslOptions); -PHP_METHOD(HttpClient, addCookies); -PHP_METHOD(HttpClient, getCookies); -PHP_METHOD(HttpClient, setCookies); -PHP_METHOD(HttpClient, enableCookies); -PHP_METHOD(HttpClient, resetCookies); -PHP_METHOD(HttpClient, flushCookies); -PHP_METHOD(HttpClient, setRequest); -PHP_METHOD(HttpClient, getRequest); -PHP_METHOD(HttpClient, send); -PHP_METHOD(HttpClient, request); -PHP_METHOD(HttpClient, getResponseMessage); -PHP_METHOD(HttpClient, getRequestMessage); -PHP_METHOD(HttpClient, getHistory); -PHP_METHOD(HttpClient, clearHistory); -PHP_METHOD(HttpClient, getResponseMessageClass); -PHP_METHOD(HttpClient, setResponseMessageClass); +PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); +PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to); +PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h); +PHP_HTTP_API void php_http_client_free(php_http_client_t **h); -PHP_MINIT_FUNCTION(http_client); +PHP_HTTP_API STATUS php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue); +PHP_HTTP_API STATUS php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request); -#endif +PHP_HTTP_API STATUS php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout); +PHP_HTTP_API int php_http_client_once(php_http_client_t *h); + +PHP_HTTP_API STATUS php_http_client_exec(php_http_client_t *h); +PHP_HTTP_API void php_http_client_reset(php_http_client_t *h); + +PHP_HTTP_API STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg); +PHP_HTTP_API STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr); -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ +typedef int (*php_http_client_enqueue_cmp_func_t)(php_http_client_enqueue_t *cmp, void *arg); +/* compare with request message pointer if compare_func is NULL */ +PHP_HTTP_API php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func); +PHP_MINIT_FUNCTION(http_client); +PHP_MSHUTDOWN_FUNCTION(http_client); + +#endif diff --git a/php_http_client_curl.c b/php_http_client_curl.c new file mode 100644 index 0000000..fb8ecf6 --- /dev/null +++ b/php_http_client_curl.c @@ -0,0 +1,1977 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2011, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "php_http_api.h" +#include "php_http_client.h" + +#if PHP_HTTP_HAVE_CURL + +#if PHP_HTTP_HAVE_EVENT +# include +# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) +# 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) +# endif +# ifndef DBG_EVENTS +# define DBG_EVENTS 0 +# endif +#endif + +typedef struct php_http_client_curl { + CURLM *handle; + + int unfinished; /* int because of curl_multi_perform() */ + +#if PHP_HTTP_HAVE_EVENT + 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; + php_http_client_t *client; + php_http_client_progress_state_t progress; + + php_http_client_enqueue_t queue; + + struct { + php_http_message_parser_t *parser; + php_http_message_t *message; + php_http_buffer_t *buffer; + } request; + + struct { + php_http_message_parser_t *parser; + php_http_message_t *message; + php_http_buffer_t *buffer; + } response; + + struct { + HashTable cache; + + struct curl_slist *headers; + struct curl_slist *resolve; + php_http_buffer_t cookies; + php_http_buffer_t ranges; + + long redirects; + unsigned range_request:1; + unsigned encode_cookies:1; + + struct { + uint count; + double delay; + } retry; + + } options; + +} php_http_client_curl_handler_t; + +typedef struct php_http_curle_storage { + char *url; + char *cookiestore; + char errorbuffer[0x100]; +} php_http_curle_storage_t; + +static inline php_http_curle_storage_t *php_http_curle_get_storage(CURL *ch) { + php_http_curle_storage_t *st = NULL; + + curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st); + + if (!st) { + st = pecalloc(1, sizeof(*st), 1); + curl_easy_setopt(ch, CURLOPT_PRIVATE, st); + curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); + } + + return st; +} + +static void *php_http_curle_ctor(void *opaque, void *init_arg TSRMLS_DC) +{ + void *ch; + + if ((ch = curl_easy_init())) { + php_http_curle_get_storage(ch); + return ch; + } + return NULL; +} + +static void *php_http_curle_copy(void *opaque, void *handle TSRMLS_DC) +{ + void *ch; + + if ((ch = curl_easy_duphandle(handle))) { + curl_easy_reset(ch); + php_http_curle_get_storage(ch); + return ch; + } + return NULL; +} + +static void php_http_curle_dtor(void *opaque, void *handle TSRMLS_DC) +{ + php_http_curle_storage_t *st = php_http_curle_get_storage(handle); + + curl_easy_cleanup(handle); + + if (st) { + if (st->url) { + pefree(st->url, 1); + } + if (st->cookiestore) { + pefree(st->cookiestore, 1); + } + pefree(st, 1); + } +} + +static php_resource_factory_ops_t php_http_curle_resource_factory_ops = { + php_http_curle_ctor, + php_http_curle_copy, + php_http_curle_dtor +}; + +static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC) +{ + return curl_multi_init(); +} + +static void php_http_curlm_dtor(void *opaque, void *handle TSRMLS_DC) +{ + curl_multi_cleanup(handle); +} + +static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { + php_http_curlm_ctor, + NULL, + php_http_curlm_dtor +}; + +/* curl callbacks */ + +static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, void *ctx) +{ + php_http_message_body_t *body = ctx; + + if (body) { + TSRMLS_FETCH_FROM_CTX(body->ts); + return php_stream_read(php_http_message_body_stream(body), data, len * n); + } + return 0; +} + +static int php_http_curle_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow) +{ + 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) { + h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); + } + + return 0; +} + +static curlioerr php_http_curle_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx) +{ + php_http_message_body_t *body = ctx; + + if (cmd != CURLIOCMD_RESTARTREAD) { + return CURLIOE_UNKNOWNCMD; + } + + if (body) { + TSRMLS_FETCH_FROM_CTX(body->ts); + + if (SUCCESS == php_stream_rewind(php_http_message_body_stream(body))) { + return CURLIOE_OK; + } + } + + return CURLIOE_FAILRESTART; +} + +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 flags = 0; + + /* catch progress */ + switch (type) { + case CURLINFO_TEXT: + if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) { + h->progress.info = "resolve"; + } else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) { + h->progress.info = "connect"; + } else if (php_memnstr(data, ZEND_STRL("Found bundle for host"), data + length)) { + h->progress.info = "connect"; + } else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) { + h->progress.info = "connected"; + } else if (php_memnstr(data, ZEND_STRL("Re-using existing connection!"), data + length)) { + h->progress.info = "connected"; + } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) { + h->progress.info = "not disconnected"; + } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) { + h->progress.info = "disconnected"; + } else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) { + h->progress.info = "redirect"; + } else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) { + h->progress.info = "timeout"; + } else { + h->progress.info = data; + } + if (h->client->callback.progress.func) { + 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: + case CURLINFO_SSL_DATA_OUT: + h->progress.info = "send"; + break; + case CURLINFO_HEADER_IN: + case CURLINFO_DATA_IN: + case CURLINFO_SSL_DATA_IN: + h->progress.info = "receive"; + break; + default: + break; + } + /* process data */ + switch (type) { + case CURLINFO_HEADER_IN: + case CURLINFO_DATA_IN: + php_http_buffer_append(h->response.buffer, data, length); + + if (h->options.redirects) { + flags |= PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS; + } + + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->response.parser, h->response.buffer, flags, &h->response.message)) { + return -1; + } + break; + + case CURLINFO_HEADER_OUT: + case CURLINFO_DATA_OUT: + php_http_buffer_append(h->request.buffer, data, length); + + if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->request.parser, h->request.buffer, flags, &h->request.message)) { + return -1; + } + break; + default: + break; + } + +#if 0 + /* debug */ + _dpf(type, data, length); +#endif + + return 0; +} + +static int php_http_curle_dummy_callback(char *data, size_t n, size_t l, void *s) +{ + return n*l; +} + +static STATUS php_http_curle_get_info(CURL *ch, HashTable *info) +{ + char *c; + long l; + double d; + struct curl_slist *s, *p; + zval *subarray, array; + INIT_PZVAL_ARRAY(&array, info); + + /* BEGIN::CURLINFO */ + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) { + add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) { + add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) { + add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) { + add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) { + add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) { + add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) { + add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) { + add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) { + add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) { + add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) { + add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) { + add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) { + add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) { + add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { + add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) { + add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) { + add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) { + add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) { + add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) { + add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) { + add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) { + add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) { + add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) { + add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) { + add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) { + MAKE_STD_ZVAL(subarray); + array_init(subarray); + for (p = s; p; p = p->next) { + if (p->data) { + add_next_index_string(subarray, p->data, 1); + } + } + add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray); + curl_slist_free_all(s); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_COOKIELIST, &s)) { + MAKE_STD_ZVAL(subarray); + array_init(subarray); + for (p = s; p; p = p->next) { + if (p->data) { + add_next_index_string(subarray, p->data, 1); + } + } + add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray); + curl_slist_free_all(s); + } + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) { + add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1); + } +#if PHP_HTTP_CURL_VERSION(7,19,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) { + add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,19,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) { + add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,19,4) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) { + add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,21,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) { + add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,21,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) { + add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1); + } +#endif +#if PHP_HTTP_CURL_VERSION(7,21,0) + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) { + add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l); + } +#endif + + /* END::CURLINFO */ + +#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL) + { + int i; + zval *ci_array; + struct curl_certinfo *ci; + char *colon, *keyname; + + if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) { + MAKE_STD_ZVAL(ci_array); + array_init(ci_array); + + for (i = 0; i < ci->num_of_certs; ++i) { + s = ci->certinfo[i]; + + MAKE_STD_ZVAL(subarray); + array_init(subarray); + for (p = s; p; p = p->next) { + if (p->data) { + if ((colon = strchr(p->data, ':'))) { + keyname = estrndup(p->data, colon - p->data); + add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1); + efree(keyname); + } else { + add_next_index_string(subarray, p->data, 1); + } + } + } + add_next_index_zval(ci_array, subarray); + } + add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array); + } + } +#endif + add_assoc_string_ex(&array, "error", sizeof("error"), php_http_curle_get_storage(ch)->errorbuffer, 1); + + return SUCCESS; +} + +static int compare_queue(php_http_client_enqueue_t *e, void *handle) +{ + return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle; +} + +static void php_http_curlm_responsehandler(php_http_client_t *context) +{ + int remaining = 0; + php_http_client_enqueue_t *enqueue; + php_http_client_curl_t *curl = context->ctx; + TSRMLS_FETCH_FROM_CTX(context->ts); + + do { + CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining); + + 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_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "%s; %s (%s)", curl_easy_strerror(msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url)); + } + + if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) { + php_http_client_curl_handler_t *handler = enqueue->opaque; + + context->callback.response.func(context->callback.response.arg, context, &handler->queue, &handler->request.message, &handler->response.message); + } + } + } while (remaining); +} + +#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, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished))); + + if (CURLM_OK != rc) { + php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "%s", curl_multi_strerror(rc)); + } + + php_http_curlm_responsehandler(context); + } +} + +static void php_http_curlm_event_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, "E"); +#endif + if (curl->useevents) { + CURLMcode rc = CURLE_OK; + TSRMLS_FETCH_FROM_CTX(context->ts); + + while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished))); + + if (CURLM_OK != rc) { + php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "%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; + +#if DBG_EVENTS + fprintf(stderr, "S"); +#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, 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_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "Unknown socket action %d", action); + return -1; + } + + event_assign(&ev->evnt, PHP_HTTP_G->curl.event_base, sock, events, php_http_curlm_event_callback, context); + event_add(&ev->evnt, NULL); + } + + 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; + TSRMLS_FETCH_FROM_CTX(context->ts); + + if (!event_initialized(curl->timeout)) { + event_assign(curl->timeout, PHP_HTTP_G->curl.event_base, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context); + } else if (event_pending(curl->timeout, EV_TIMEOUT, NULL)) { + event_del(curl->timeout); + } + + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + + event_add(curl->timeout, &timeout); + } + } +} + +#endif /* HAVE_EVENT */ + +/* curl options */ + +static php_http_options_t php_http_curle_options; + +#define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN 0x0001 +#define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR 0x0002 +#define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS 0x0004 + +static STATUS php_http_curle_option_set_ssl_verifyhost(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_SSL_VERIFYHOST, Z_BVAL_P(val) ? 2 : 0)) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (val) { + php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); + + if (storage->cookiestore) { + pefree(storage->cookiestore, 1); + } + storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1); + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore) + ) { + return FAILURE; + } + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { + if (curl->options.encode_cookies) { + if (SUCCESS == php_http_url_encode_hash_ex(HASH_OF(val), &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0 TSRMLS_CC)) { + php_http_buffer_fix(&curl->options.cookies); + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { + return FAILURE; + } + } else { + return FAILURE; + } + } else { + HashPosition pos; + php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0); + zval **cookie_val; + + FOREACH_KEYVAL(pos, val, cookie_key, cookie_val) { + zval *zv = php_http_ztyp(IS_STRING, *cookie_val); + + php_http_array_hashkey_stringify(&cookie_key); + php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(zv)); + php_http_array_hashkey_stringfree(&cookie_key); + + zval_ptr_dtor(&zv); + } + + php_http_buffer_fix(&curl->options.cookies); + if (curl->options.cookies.used) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { + return FAILURE; + } + } + } + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + curl->options.encode_cookies = Z_BVAL_P(val); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (Z_LVAL_P(val)) { + if (Z_LVAL_P(val) > 0) { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) { + return FAILURE; + } + } else { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) PHP_HTTP_G->env.request.time + Z_LVAL_P(val))) { + return FAILURE; + } + } + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) { + return FAILURE; + } + } else { + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0) + ) { + return FAILURE; + } + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + if (Z_BVAL_P(val)) { + curl->options.headers = curl_slist_append(curl->options.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5"); + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_etag(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + php_http_buffer_t header; + zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"')); + + php_http_buffer_init(&header); + php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val)); + php_http_buffer_fix(&header); + curl->options.headers = curl_slist_append(curl->options.headers, header.data); + php_http_buffer_dtor(&header); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_range(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + php_http_buffer_reset(&curl->options.ranges); + + if (val && Z_TYPE_P(val) != IS_NULL) { + HashPosition pos; + zval **rr, **rb, **re; + + FOREACH_VAL(pos, val, rr) { + if (Z_TYPE_PP(rr) == IS_ARRAY) { + if (2 == php_http_array_list(Z_ARRVAL_PP(rr) TSRMLS_CC, 2, &rb, &re)) { + 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))) && + ((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)))) { + zval *rbl = php_http_ztyp(IS_LONG, *rb); + zval *rel = php_http_ztyp(IS_LONG, *re); + + if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) { + php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel)); + } + zval_ptr_dtor(&rbl); + zval_ptr_dtor(&rel); + } + + } + } + } + + if (curl->options.ranges.used) { + curl->options.range_request = 1; + /* ditch last comma */ + curl->options.ranges.data[curl->options.ranges.used - 1] = '\0'; + } + } + + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_resume(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + + if (Z_LVAL_P(val) > 0) { + curl->options.range_request = 1; + } + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + curl->options.retry.delay = Z_DVAL_P(val); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + + curl->options.retry.count = Z_LVAL_P(val); + return SUCCESS; +} + +static STATUS php_http_curle_option_set_redirect(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_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val)) + ) { + return FAILURE; + } + return SUCCESS; +} + +static STATUS php_http_curle_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + long localport = 0, localportrange = 0; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { + zval **z_port_start, *zps_copy = NULL, **z_port_end, *zpe_copy = NULL; + + switch (php_http_array_list(Z_ARRVAL_P(val) TSRMLS_CC, 2, &z_port_start, &z_port_end)) { + case 2: + zps_copy = php_http_ztyp(IS_LONG, *z_port_start); + zpe_copy = php_http_ztyp(IS_LONG, *z_port_end); + localportrange = labs(Z_LVAL_P(zps_copy)-Z_LVAL_P(zpe_copy))+1L; + /* no break */ + case 1: + if (!zps_copy) { + zps_copy = php_http_ztyp(IS_LONG, *z_port_start); + } + 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); + zval_ptr_dtor(&zps_copy); + if (zpe_copy) { + zval_ptr_dtor(&zpe_copy); + } + break; + default: + break; + } + } + if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport) + || CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange) + ) { + return FAILURE; + } + return SUCCESS; +} + +#if PHP_HTTP_CURL_VERSION(7,21,3) +static STATUS php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (val && Z_TYPE_P(val) != IS_NULL) { + php_http_array_hashkey_t key = php_http_array_hashkey_init(0); + HashPosition pos; + zval **data; + + FOREACH_KEYVAL(pos, val, key, data) { + zval *cpy = php_http_ztyp(IS_STRING, *data); + curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy)); + zval_ptr_dtor(&cpy); + } + + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) { + return FAILURE; + } + } else { + if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) { + return FAILURE; + } + } + return SUCCESS; +} +#endif + +static void php_http_curle_options_init(php_http_options_t *registry TSRMLS_DC) +{ + php_http_option_t *opt; + + /* proxy */ + if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG); + php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG); + if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG); + php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL); +#if PHP_HTTP_CURL_VERSION(7,19,4) + php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING); +#endif + + /* dns */ + if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) { + Z_LVAL(opt->defval) = 60; + } + php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG); +#if PHP_HTTP_CURL_VERSION(7,21,3) + if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_resolve; + } +#endif +#if PHP_HTTP_CURL_VERSION(7,24,0) + if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } +#endif + + /* limits */ + php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG); + php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG); + + /* LSF weirdance + php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG); + php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG); + */ + + /* connection handling */ + /* crashes + if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) { + Z_LVAL(opt->defval) = 5; + } + */ + php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL); + php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL); + + /* outgoing interface */ + php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING); + if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_portrange; + } + + /* another endpoint port */ + php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG); + + /* RFC4007 zone_id */ +#if PHP_HTTP_CURL_VERSION(7,19,0) + php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG); +#endif + + /* auth */ + if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG); + + /* redirects */ + if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) { + opt->setter = php_http_curle_option_set_redirect; + } + php_http_option_register(registry, ZEND_STRL("unrestrictedauth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL); +#if PHP_HTTP_CURL_VERSION(7,19,1) + php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_BOOL); +#else + php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POST301, IS_BOOL); +#endif + + /* retries */ + if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) { + opt->setter = php_http_curle_option_set_retrycount; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) { + opt->setter = php_http_curle_option_set_retrydelay; + } + + /* referer */ + if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) { + ZVAL_BOOL(&opt->defval, 1); + } + + /* useragent */ + if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) { + /* don't check strlen, to allow sending no useragent at all */ + ZVAL_STRING(&opt->defval, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")", 0); + } + + /* resume */ + if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) { + opt->setter = php_http_curle_option_set_resume; + } + /* ranges */ + if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_range; + } + + /* etag */ + if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN; + opt->setter = php_http_curle_option_set_etag; + } + + /* compression */ + if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) { + opt->setter = php_http_curle_option_set_compress; + } + + /* lastmodified */ + if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) { + opt->setter = php_http_curle_option_set_lastmodified; + } + + /* cookies */ + if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) { + opt->setter = php_http_curle_option_set_encodecookies; + ZVAL_BOOL(&opt->defval, 1); + } + if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) { + opt->setter = php_http_curle_option_set_cookies; + } + + /* cookiesession, don't load session cookies from cookiestore */ + php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL); + /* 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; + opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR; + opt->setter = php_http_curle_option_set_cookiestore; + } + + /* maxfilesize */ + php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG); + + /* http protocol version */ + php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG); + + /* timeouts */ + if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) { + opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS; + Z_DVAL(opt->defval) = 3; + } + + /* tcp */ +#if PHP_HTTP_CURL_VERSION(7,25,0) + php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL); + if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) { + Z_LVAL(opt->defval) = 60; + } + if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) { + Z_LVAL(opt->defval) = 60; + } +#endif + + /* 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; + } + php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING); + php_http_option_register(registry, ZEND_STRL("certpasswd"), CURLOPT_SSLCERTPASSWD, IS_STRING); + + 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; + } + php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING); + php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING); + 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; + } + 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); +#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("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; + } +# 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; + } +# 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); +#endif + } +} + +static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *options, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + zval *option; + + if ((option = php_http_option_get(opt, options, NULL))) { + option = php_http_ztyp(opt->type, option); + zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL); + } + return option; +} + +static STATUS php_http_curle_set_option(php_http_option_t *opt, zval *val, void *userdata) +{ + php_http_client_curl_handler_t *curl = userdata; + CURL *ch = curl->handle; + zval tmp; + STATUS rv = SUCCESS; + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + if (!val) { + val = &opt->defval; + } + + switch (opt->type) { + case IS_BOOL: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) { + rv = FAILURE; + } + break; + + case IS_LONG: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) { + rv = FAILURE; + } + break; + + case IS_STRING: + if (!(opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) || Z_STRLEN_P(val)) { + if (!(opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) || !Z_STRVAL_P(val) || SUCCESS == php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) { + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val))) { + rv = FAILURE; + } + } + } + break; + + case IS_DOUBLE: + if (opt->flags & PHP_HTTP_CURLE_OPTION_TRANSFORM_MS) { + tmp = *val; + Z_DVAL(tmp) *= 1000; + val = &tmp; + } + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) { + rv = FAILURE; + } + break; + + case IS_ARRAY: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else if (Z_TYPE_P(val) != IS_NULL) { + rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), curl); + } + break; + + default: + if (opt->setter) { + rv = opt->setter(opt, val, curl); + } else { + rv = FAILURE; + } + break; + } + if (rv != SUCCESS) { + php_http_error(HE_NOTICE, PHP_HTTP_E_CLIENT, "Could not set option %s", opt->name.s); + } + return rv; +} + + +/* client ops */ + +static STATUS php_http_client_curl_handler_reset(php_http_client_curl_handler_t *curl) +{ + CURL *ch = curl->handle; + php_http_curle_storage_t *st; + + if ((st = php_http_curle_get_storage(ch))) { + if (st->url) { + pefree(st->url, 1); + st->url = NULL; + } + if (st->cookiestore) { + pefree(st->cookiestore, 1); + st->cookiestore = NULL; + } + st->errorbuffer[0] = '\0'; + } + + curl_easy_setopt(ch, CURLOPT_URL, NULL); + /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */ +#if PHP_HTTP_CURL_VERSION(7,19,1) + curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL); + curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL); + curl_easy_setopt(ch, CURLOPT_USERNAME, NULL); + curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL); +#endif + +#if PHP_HTTP_CURL_VERSION(7,21,3) + if (curl->options.resolve) { + curl_slist_free_all(curl->options.resolve); + curl->options.resolve = NULL; + } +#endif + curl->options.retry.count = 0; + curl->options.retry.delay = 0; + curl->options.redirects = 0; + curl->options.encode_cookies = 1; + + if (curl->options.headers) { + curl_slist_free_all(curl->options.headers); + curl->options.headers = NULL; + } + + php_http_buffer_reset(&curl->options.cookies); + php_http_buffer_reset(&curl->options.ranges); + + return SUCCESS; +} + +static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf) +{ + void *handle; + php_http_client_curl_handler_t *handler; + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (!(handle = php_resource_factory_handle_ctor(rf, NULL TSRMLS_CC))) { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to initialize curl handle"); + return NULL; + } + + handler = ecalloc(1, sizeof(*handler)); + handler->rf = rf; + handler->client = h; + handler->handle = handle; + handler->request.buffer = php_http_buffer_init(NULL); + handler->request.parser = php_http_message_parser_init(NULL TSRMLS_CC); + handler->request.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + handler->response.buffer = php_http_buffer_init(NULL); + handler->response.parser = php_http_message_parser_init(NULL TSRMLS_CC); + handler->response.message = php_http_message_init(NULL, 0, NULL TSRMLS_CC); + php_http_buffer_init(&handler->options.cookies); + php_http_buffer_init(&handler->options.ranges); + zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0); + +#if defined(ZTS) + curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); +#endif + curl_easy_setopt(handle, CURLOPT_HEADER, 0L); + curl_easy_setopt(handle, CURLOPT_FILETIME, 1L); + curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L); + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curle_dummy_callback); + curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback); + curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curle_read_callback); + curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curle_ioctl_callback); + curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback); + curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler); + curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler); + + php_http_client_curl_handler_reset(handler); + + return handler; +} + + +static STATUS php_http_client_curl_handler_prepare(php_http_client_curl_handler_t *curl, php_http_client_enqueue_t *enqueue) +{ + size_t body_size; + php_http_message_t *msg = enqueue->request; + php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle); + TSRMLS_FETCH_FROM_CTX(curl->client->ts); + + /* request url */ + if (!PHP_HTTP_INFO(msg).request.url) { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot request empty URL"); + return FAILURE; + } + storage->errorbuffer[0] = '\0'; + if (storage->url) { + pefree(storage->url, 1); + } + storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 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_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_METHOD, "Cannot use empty request method"); + return FAILURE; + } + break; + } + } + + /* request headers */ + php_http_message_update_headers(msg); + if (zend_hash_num_elements(&msg->hdrs)) { + php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0); + zval **header_val; + HashPosition pos; + php_http_buffer_t header; + + php_http_buffer_init(&header); + FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) { + if (header_key.type == HASH_KEY_IS_STRING) { + zval *header_cpy = php_http_ztyp(IS_STRING, *header_val); + + php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy)); + php_http_buffer_fix(&header); + curl->options.headers = curl_slist_append(curl->options.headers, header.data); + php_http_buffer_reset(&header); + + zval_ptr_dtor(&header_cpy); + } + } + php_http_buffer_dtor(&header); + curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers); + } + + /* attach request body */ + if ((body_size = php_http_message_body_size(msg->body))) { + /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the + * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.« + * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the + * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method + * does not allow a request body. + */ + php_stream_rewind(php_http_message_body_stream(msg->body)); + curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, msg->body); + 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); + } + + php_http_options_apply(&php_http_curle_options, enqueue->options, curl); + + return SUCCESS; +} + +static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler) +{ + TSRMLS_FETCH_FROM_CTX(handler->client->ts); + + curl_easy_setopt(handler->handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL); + curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL); + + php_resource_factory_handle_dtor(handler->rf, handler->handle TSRMLS_CC); + php_resource_factory_free(&handler->rf); + + php_http_message_parser_free(&handler->request.parser); + php_http_message_free(&handler->request.message); + php_http_buffer_free(&handler->request.buffer); + php_http_message_parser_free(&handler->response.parser); + php_http_message_free(&handler->response.message); + php_http_buffer_free(&handler->response.buffer); + php_http_buffer_dtor(&handler->options.ranges); + php_http_buffer_dtor(&handler->options.cookies); + zend_hash_destroy(&handler->options.cache); + + if (handler->options.headers) { + curl_slist_free_all(handler->options.headers); + handler->options.headers = NULL; + } + + efree(handler); +} + +static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void *handle) +{ + php_http_client_curl_t *curl; + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Failed to initialize curl handle"); + return NULL; + } + + curl = ecalloc(1, sizeof(*curl)); + curl->handle = handle; + curl->unfinished = 0; + h->ctx = curl; + + return h; +} + +static void php_http_client_curl_dtor(php_http_client_t *h) +{ + php_http_client_curl_t *curl = h->ctx; + TSRMLS_FETCH_FROM_CTX(h->ts); + +#if PHP_HTTP_HAVE_EVENT + if (curl->timeout) { + efree(curl->timeout); + curl->timeout = NULL; + } +#endif + curl->unfinished = 0; + + php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); + + efree(curl); + h->ctx = NULL; +} + +static void queue_dtor(php_http_client_enqueue_t *e) +{ + php_http_client_curl_handler_t *handler = e->opaque; + + if (handler->queue.dtor) { + e->opaque = handler->queue.opaque; + handler->queue.dtor(e); + } + php_http_client_curl_handler_dtor(handler); +} + +static php_resource_factory_t *create_rf(const char *url TSRMLS_DC) +{ + php_url *purl; + php_resource_factory_t *rf = NULL; + + if ((purl = php_url_parse(url))) { + char *id_str = NULL; + size_t id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(purl->host), purl->port ? purl->port : 80); + php_persistent_handle_factory_t *pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC); + + if (pf) { + rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void*)) php_persistent_handle_abandon); + } + + php_url_free(purl); + efree(id_str); + } + + if (!rf) { + rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL); + } + + return rf; +} + +static STATUS php_http_client_curl_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) +{ + CURLMcode rs; + php_http_client_curl_t *curl = h->ctx; + php_http_client_curl_handler_t *handler; + php_http_client_progress_state_t *progress; + TSRMLS_FETCH_FROM_CTX(h->ts); + + handler = php_http_client_curl_handler_init(h, create_rf(enqueue->request->http.info.request.url TSRMLS_CC)); + if (!handler) { + return FAILURE; + } + + if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) { + php_http_client_curl_handler_dtor(handler); + return FAILURE; + } + + handler->queue = *enqueue; + enqueue->opaque = handler; + enqueue->dtor = queue_dtor; + + if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, handler->handle))) { + zend_llist_add_element(&h->requests, enqueue); + ++curl->unfinished; + + if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { + progress->info = "start"; + h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); + progress->started = 1; + } + + return SUCCESS; + } else { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Could not enqueue request: %s", curl_multi_strerror(rs)); + return FAILURE; + } +} + +static STATUS php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) +{ + CURLMcode rs; + php_http_client_curl_t *curl = h->ctx; + php_http_client_curl_handler_t *handler = enqueue->opaque; + TSRMLS_FETCH_FROM_CTX(h->ts); + + if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, handler->handle))) { + zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); + return SUCCESS; + } else { + php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Could not dequeue request: %s", curl_multi_strerror(rs)); + } + + return FAILURE; +} + +static void php_http_client_curl_reset(php_http_client_t *h) +{ + zend_llist_element *next_el, *this_el; + + for (this_el = h->requests.head; this_el; this_el = next_el) { + next_el = this_el->next; + php_http_client_curl_dequeue(h, (void *) this_el->data); + } +} + +#ifdef PHP_WIN32 +# define SELECT_ERROR SOCKET_ERROR +#else +# define SELECT_ERROR -1 +#endif + +static STATUS php_http_client_curl_wait(php_http_client_t *h, struct timeval *custom_timeout) +{ + int MAX; + fd_set R, W, E; + struct timeval timeout; + php_http_client_curl_t *curl = h->ctx; + +#if PHP_HTTP_HAVE_EVENT + if (curl->useevents) { + TSRMLS_FETCH_FROM_CTX(h->ts); + + php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "not implemented"); + return FAILURE; + } +#endif + + FD_ZERO(&R); + FD_ZERO(&W); + FD_ZERO(&E); + + if (CURLM_OK == curl_multi_fdset(curl->handle, &R, &W, &E, &MAX)) { + if (custom_timeout && timerisset(custom_timeout)) { + timeout = *custom_timeout; + } else { + long max_tout = 1000; + + if ((CURLM_OK == curl_multi_timeout(curl->handle, &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; + } + } + + if (MAX == -1) { + php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC)); + return SUCCESS; + } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) { + return SUCCESS; + } + } + return FAILURE; +} + +static int php_http_client_curl_once(php_http_client_t *h) +{ + php_http_client_curl_t *curl = h->ctx; + +#if PHP_HTTP_HAVE_EVENT + if (curl->useevents) { + TSRMLS_FETCH_FROM_CTX(h->ts); + php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "not implemented"); + return FAILURE; + } +#endif + + while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle, &curl->unfinished)); + + php_http_curlm_responsehandler(h); + + return curl->unfinished; + +} + +static STATUS php_http_client_curl_exec(php_http_client_t *h) +{ + TSRMLS_FETCH_FROM_CTX(h->ts); + +#if PHP_HTTP_HAVE_EVENT + php_http_client_curl_t *curl = h->ctx; + + if (curl->useevents) { + php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h); + do { + int ev_rc = event_base_dispatch(PHP_HTTP_G->curl.event_base); + +#if DBG_EVENTS + fprintf(stderr, "%c", "X.0"[ev_rc+1]); +#endif + + if (ev_rc < 0) { + php_http_error(HE_ERROR, PHP_HTTP_E_RUNTIME, "Error in event_base_dispatch()"); + return FAILURE; + } + } while (curl->unfinished); + } else +#endif + { + while (php_http_client_curl_once(h)) { + 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_error(HE_WARNING, PHP_HTTP_E_SOCKET, "WinSock error: %d", WSAGetLastError()); +#else + php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, strerror(errno)); +#endif + return FAILURE; + } + } + } + + return SUCCESS; +} + +static STATUS php_http_client_curl_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) +{ + php_http_client_curl_t *curl = h->ctx; + + switch (opt) { + case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING: + if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { + return FAILURE; + } + break; + + case PHP_HTTP_CLIENT_OPT_USE_EVENTS: +#if PHP_HTTP_HAVE_EVENT + if ((curl->useevents = *((zend_bool *) arg))) { + 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); + } + break; +#endif + + default: + return FAILURE; + } + return SUCCESS; +} + +static STATUS 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; + + switch (opt) { + case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO: + if ((enqueue = php_http_client_enqueued(h, arg, NULL))) { + php_http_client_curl_handler_t *handler = enqueue->opaque; + + *((php_http_client_progress_state_t **) res) = &handler->progress; + return SUCCESS; + } + break; + + case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO: + if ((enqueue = php_http_client_enqueued(h, arg, NULL))) { + php_http_client_curl_handler_t *handler = enqueue->opaque; + + php_http_curle_get_info(handler->handle, *(HashTable **) res); + return SUCCESS; + } + break; + + default: + break; + } + + return FAILURE; +} + +static php_http_client_ops_t php_http_client_curl_ops = { + &php_http_curlm_resource_factory_ops, + php_http_client_curl_init, + NULL /* copy */, + php_http_client_curl_dtor, + php_http_client_curl_reset, + php_http_client_curl_exec, + php_http_client_curl_wait, + php_http_client_curl_once, + php_http_client_curl_enqueue, + php_http_client_curl_dequeue, + php_http_client_curl_setopt, + php_http_client_curl_getopt +}; + +PHP_HTTP_API php_http_client_ops_t *php_http_client_curl_get_ops(void) +{ + return &php_http_client_curl_ops; +} + +PHP_MINIT_FUNCTION(http_client_curl) +{ + php_http_options_t *options; + php_http_client_driver_t driver = { + &php_http_client_curl_ops + }; + + if (SUCCESS != php_http_client_driver_add(ZEND_STRL("curl"), &driver)) { + return FAILURE; + } + + if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl"), &php_http_curlm_resource_factory_ops, NULL, NULL TSRMLS_CC)) { + return FAILURE; + } + if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http\\Client\\Curl\\Request"), &php_http_curle_resource_factory_ops, NULL, NULL TSRMLS_CC)) { + return FAILURE; + } + + if ((options = php_http_options_init(&php_http_curle_options, 1))) { + options->getter = php_http_curle_get_option; + options->setter = php_http_curle_set_option; + + php_http_curle_options_init(options TSRMLS_CC); + } + + /* + * HTTP Protocol Version Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT); + + /* + * SSL Version Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1, CONST_CS|CONST_PERSISTENT); + 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); + + /* + * DNS IPvX resolving + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V4", CURL_IPRESOLVE_V4, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V6", CURL_IPRESOLVE_V6, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER, CONST_CS|CONST_PERSISTENT); + + /* + * Auth Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BASIC", CURLAUTH_BASIC, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS|CONST_PERSISTENT); +#if PHP_HTTP_CURL_VERSION(7,19,3) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE, CONST_CS|CONST_PERSISTENT); +#endif + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NTLM", CURLAUTH_NTLM, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_ANY", CURLAUTH_ANY, CONST_CS|CONST_PERSISTENT); + + /* + * Proxy Type Constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4", CURLPROXY_SOCKS4, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4A", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP", CURLPROXY_HTTP, CONST_CS|CONST_PERSISTENT); +# if PHP_HTTP_CURL_VERSION(7,19,4) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0, CONST_CS|CONST_PERSISTENT); +# endif + + /* + * Post Redirection Constants + */ +#if PHP_HTTP_CURL_VERSION(7,19,1) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_301", CURL_REDIR_POST_301, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_302", CURL_REDIR_POST_302, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_ALL", CURL_REDIR_POST_ALL, CONST_CS|CONST_PERSISTENT); +#endif + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_client_curl) +{ + php_http_options_dtor(&php_http_curle_options); + return SUCCESS; +} + +#if PHP_HTTP_HAVE_EVENT +PHP_RINIT_FUNCTION(http_client_curl) +{ + if (!PHP_HTTP_G->curl.event_base && !(PHP_HTTP_G->curl.event_base = event_base_new())) { + return FAILURE; + } + return SUCCESS; +} +PHP_RSHUTDOWN_FUNCTION(http_client_curl) +{ + if (PHP_HTTP_G->curl.event_base) { + event_base_free(PHP_HTTP_G->curl.event_base); + PHP_HTTP_G->curl.event_base = NULL; + } + return SUCCESS; +} +#endif /* PHP_HTTP_HAVE_EVENT */ + +#endif /* PHP_HTTP_HAVE_CURL */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client_curl.h b/php_http_client_curl.h new file mode 100644 index 0000000..51320a2 --- /dev/null +++ b/php_http_client_curl.h @@ -0,0 +1,40 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2011, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_HTTP_CLIENT_CURL_H +#define PHP_HTTP_CLIENT_CURL_H + +#if PHP_HTTP_HAVE_CURL + +#if PHP_HTTP_HAVE_EVENT +struct php_http_curl_globals { + void *event_base; +}; + +PHP_RINIT_FUNCTION(http_client_curl); +PHP_RSHUTDOWN_FUNCTION(http_client_curl); +#endif /* PHP_HTTP_HAVE_EVENT */ + +PHP_MINIT_FUNCTION(http_client_curl); +PHP_MSHUTDOWN_FUNCTION(http_client_curl); +#endif /* PHP_HTTP_HAVE_CURL */ + +#endif /* PHP_HTTP_CLIENT_CURL_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_http_client_datashare.c b/php_http_client_datashare.c deleted file mode 100644 index c339c20..0000000 --- a/php_http_client_datashare.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" -#include "php_http_client_datashare.h" - -static int php_http_client_datashare_compare_handles(void *h1, void *h2); - -PHP_HTTP_API php_http_client_datashare_t *php_http_client_datashare_init(php_http_client_datashare_t *h, php_http_client_datashare_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC) -{ - php_http_client_datashare_t *free_h = NULL; - - if (!h) { - free_h = h = emalloc(sizeof(*h)); - } - memset(h, 0, sizeof(*h)); - - zend_llist_init(&h->clients, sizeof(zval *), ZVAL_PTR_DTOR, 0); - h->ops = ops; - if (rf) { - h->rf = rf; - } else if (ops->rsrc) { - h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL); - } - TSRMLS_SET_CTX(h->ts); - - if (h->ops->init) { - if (!(h = h->ops->init(h, init_arg))) { - if (free_h) { - efree(free_h); - } - } - } - - return h; -} - -PHP_HTTP_API php_http_client_datashare_t *php_http_client_datashare_copy(php_http_client_datashare_t *from, php_http_client_datashare_t *to) -{ - if (from->ops->copy) { - return from->ops->copy(from, to); - } - - return NULL; -} - -PHP_HTTP_API void php_http_client_datashare_dtor(php_http_client_datashare_t *h) -{ - if (h->ops->dtor) { - h->ops->dtor(h); - } - zend_llist_destroy(&h->clients); - php_resource_factory_free(&h->rf); -} - -PHP_HTTP_API void php_http_client_datashare_free(php_http_client_datashare_t **h) -{ - php_http_client_datashare_dtor(*h); - efree(*h); - *h = NULL; -} - -PHP_HTTP_API STATUS php_http_client_datashare_attach(php_http_client_datashare_t *h, zval *client) -{ - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (h->ops->attach) { - php_http_client_object_t *obj = zend_object_store_get_object(client TSRMLS_CC); - - if (SUCCESS == h->ops->attach(h, obj->client)) { - Z_ADDREF_P(client); - zend_llist_add_element(&h->clients, &client); - return SUCCESS; - } - } - - return FAILURE; -} - -static int php_http_client_datashare_compare_handles(void *h1, void *h2) -{ - return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2)); -} - -PHP_HTTP_API STATUS php_http_client_datashare_detach(php_http_client_datashare_t *h, zval *client) -{ - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (h->ops->detach) { - php_http_client_object_t *obj = zend_object_store_get_object(client TSRMLS_CC); - - if (SUCCESS == h->ops->detach(h, obj->client)) { - zend_llist_del_element(&h->clients, client, php_http_client_datashare_compare_handles); - return SUCCESS; - } - } - return FAILURE; -} - -PHP_HTTP_API STATUS php_http_client_datashare_setopt(php_http_client_datashare_t *h, php_http_client_datashare_setopt_opt_t opt, void *arg) -{ - if (h->ops->setopt) { - return h->ops->setopt(h, opt, arg); - } - return FAILURE; -} - -static void detach(void *r, void *h TSRMLS_DC) -{ - ((php_http_client_datashare_t *) h)->ops->detach(h, ((php_http_client_object_t *) zend_object_store_get_object(*((zval **) r) TSRMLS_CC))->client); -} - -PHP_HTTP_API void php_http_client_datashare_reset(php_http_client_datashare_t *h) -{ - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (h->ops->reset) { - h->ops->reset(h); - } else if (h->ops->detach) { - zend_llist_apply_with_argument(&h->clients, detach, h TSRMLS_CC); - } - - zend_llist_clean(&h->clients); -} - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientDataShare, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientDataShare, method, 0) -#define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpClientDataShare, method, PHP_HTTP_ARGS(HttpClientDataShare, method), visibility) - -PHP_HTTP_EMPTY_ARGS(__destruct); -PHP_HTTP_EMPTY_ARGS(reset); -PHP_HTTP_EMPTY_ARGS(count); - -PHP_HTTP_BEGIN_ARGS(attach, 1) - PHP_HTTP_ARG_OBJ(http\\Client, client, 0) -PHP_HTTP_END_ARGS; -PHP_HTTP_BEGIN_ARGS(detach, 1) - PHP_HTTP_ARG_OBJ(http\\Client, client, 0) -PHP_HTTP_END_ARGS; - -static void php_http_client_datashare_object_write_prop(zval *object, zval *member, zval *value PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC); - -static zend_class_entry *php_http_client_datashare_class_entry; - -zend_class_entry *php_http_client_datashare_get_class_entry(void) -{ - return php_http_client_datashare_class_entry; -} - -static zend_function_entry php_http_client_datashare_method_entry[] = { - PHP_HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR) - PHP_HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC) - PHP_HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC) - PHP_HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC) - PHP_HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC) - EMPTY_FUNCTION_ENTRY -}; - -static zend_object_handlers php_http_client_datashare_object_handlers; - -zend_object_handlers *php_http_client_datashare_get_object_handlers(void) -{ - return &php_http_client_datashare_object_handlers; -} -static STATUS setopt(struct php_http_client_datashare *h, php_http_client_datashare_setopt_opt_t opt, void *arg) -{ - return SUCCESS; -} - -static php_http_client_datashare_ops_t php_http_client_datashare_user_ops = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - setopt, - (php_http_new_t) php_http_client_datashare_object_new_ex, - php_http_client_datashare_get_class_entry - -}; -zend_object_value php_http_client_datashare_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return php_http_client_datashare_object_new_ex(ce, NULL, NULL TSRMLS_CC); -} - -zend_object_value php_http_client_datashare_object_new_ex(zend_class_entry *ce, php_http_client_datashare_t *share, php_http_client_datashare_object_t **ptr TSRMLS_DC) -{ - zend_object_value ov; - php_http_client_datashare_object_t *o; - - o = ecalloc(1, sizeof(*o)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - ov.handle = zend_objects_store_put(o, NULL, php_http_client_datashare_object_free, NULL TSRMLS_CC); - ov.handlers = &php_http_client_datashare_object_handlers; - - if (!(o->share = share)) { - o->share = php_http_client_datashare_init(NULL, &php_http_client_datashare_user_ops, NULL, &ov TSRMLS_CC); - } - - if (ptr) { - *ptr = o; - } - - return ov; -} - -void php_http_client_datashare_object_free(void *object TSRMLS_DC) -{ - php_http_client_datashare_object_t *o = (php_http_client_datashare_object_t *) object; - - php_http_client_datashare_free(&o->share); - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(o); -} - -static zval *php_http_client_datashare_object_read_prop(zval *object, zval *member, int type PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC) -{ - zend_property_info *pi; - - if ((pi = zend_get_property_info(php_http_client_datashare_class_entry, member, 1 TSRMLS_CC))) { - if (type != BP_VAR_R) { - zval *zproxy; - php_property_proxy_t *proxy; - - proxy = php_property_proxy_init(object, pi->name, pi->name_length TSRMLS_CC); - - MAKE_STD_ZVAL(zproxy); -#ifdef Z_SET_REFCOUNT_P - Z_SET_REFCOUNT_P(zproxy, 0); -#else - zproxy->refcount = 0; -#endif - ZVAL_OBJVAL(zproxy, php_property_proxy_object_new_ex(php_property_proxy_get_class_entry(), proxy, NULL TSRMLS_CC), 0); - return zproxy; - } - } - return zend_get_std_object_handlers()->read_property(object, member, type PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC); -} - -static void php_http_client_datashare_object_write_prop(zval *object, zval *member, zval *value PHP_HTTP_ZEND_LITERAL_DC TSRMLS_DC) -{ - zend_property_info *pi; - - if ((pi = zend_get_property_info(php_http_client_datashare_class_entry, member, 1 TSRMLS_CC))) { - zend_bool enable = i_zend_is_true(value); - php_http_client_datashare_setopt_opt_t opt; - php_http_client_datashare_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); - - if (!strcmp(pi->name, "cookie")) { - opt = PHP_HTTP_CLIENT_DATASHARE_OPT_COOKIES; - } else if (!strcmp(pi->name, "dns")) { - opt = PHP_HTTP_CLIENT_DATASHARE_OPT_RESOLVER; - } else if (!strcmp(pi->name, "ssl")) { - opt = PHP_HTTP_CLIENT_DATASHARE_OPT_SSLSESSIONS; - } else { - return; - } - - if (SUCCESS != php_http_client_datashare_setopt(obj->share, opt, &enable)) { - return; - } - } - - zend_get_std_object_handlers()->write_property(object, member, value PHP_HTTP_ZEND_LITERAL_CC TSRMLS_CC); -} - -PHP_METHOD(HttpClientDataShare, __destruct) -{ - php_http_client_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - /* FIXME: move to php_http_client_datashare_dtor */ - if (SUCCESS == zend_parse_parameters_none()) { - ; /* we always want to clean up */ - } - - php_http_client_datashare_reset(obj->share); -} - -PHP_METHOD(HttpClientDataShare, count) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - RETURN_LONG(zend_llist_count(&obj->share->clients)); - } - RETURN_FALSE; -} - - -PHP_METHOD(HttpClientDataShare, attach) -{ - zval *client; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &client, php_http_client_get_class_entry())) { - php_http_client_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - RETURN_SUCCESS(php_http_client_datashare_attach(obj->share, client)); - } - RETURN_FALSE; - -} - -PHP_METHOD(HttpClientDataShare, detach) -{ - zval *client; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &client, php_http_client_get_class_entry())) { - php_http_client_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - RETURN_SUCCESS(php_http_client_datashare_detach(obj->share, client)); - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientDataShare, reset) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - php_http_client_datashare_reset(obj->share); - RETURN_TRUE; - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientDataShare, __sleep) -{ - php_http_error(HE_THROW, PHP_HTTP_E_CLIENT_DATASHARE, "cannot serialize a client datashare"); -} - -PHP_MINIT_FUNCTION(http_client_datashare) -{ - PHP_HTTP_REGISTER_CLASS(http\\Client\\DataShare, AbstractDataShare, http_client_datashare, php_http_object_get_class_entry(), ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); - php_http_client_datashare_class_entry->create_object = php_http_client_datashare_object_new; - memcpy(&php_http_client_datashare_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - php_http_client_datashare_object_handlers.clone_obj = NULL; - php_http_client_datashare_object_handlers.read_property = php_http_client_datashare_object_read_prop; - php_http_client_datashare_object_handlers.write_property = php_http_client_datashare_object_write_prop; - php_http_client_datashare_object_handlers.get_property_ptr_ptr = NULL; - - zend_class_implements(php_http_client_datashare_class_entry TSRMLS_CC, 1, spl_ce_Countable); - - zend_declare_property_bool(php_http_client_datashare_class_entry, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); - zend_declare_property_bool(php_http_client_datashare_class_entry, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); - zend_declare_property_bool(php_http_client_datashare_class_entry, ZEND_STRL("ssl"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); - - return SUCCESS; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_datashare.h b/php_http_client_datashare.h deleted file mode 100644 index 8e66b68..0000000 --- a/php_http_client_datashare.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_CLIENT_DATASHARE_H -#define PHP_HTTP_CLIENT_DATASHARE_H - -typedef enum php_http_client_datashare_setopt_opt { - PHP_HTTP_CLIENT_DATASHARE_OPT_COOKIES, - PHP_HTTP_CLIENT_DATASHARE_OPT_RESOLVER, - PHP_HTTP_CLIENT_DATASHARE_OPT_SSLSESSIONS, -} php_http_client_datashare_setopt_opt_t; - -typedef struct php_http_client_datashare *(*php_http_client_datashare_init_func_t)(struct php_http_client_datashare *h, void *init_arg); -typedef struct php_http_client_datashare *(*php_http_client_datashare_copy_func_t)(struct php_http_client_datashare *from, struct php_http_client_datashare *to); -typedef void (*php_http_client_datashare_dtor_func_t)(struct php_http_client_datashare *h); -typedef void (*php_http_client_datashare_reset_func_t)(struct php_http_client_datashare *h); -typedef STATUS (*php_http_client_datashare_attach_func_t)(struct php_http_client_datashare *h, php_http_client_t *client); -typedef STATUS (*php_http_client_datashare_detach_func_t)(struct php_http_client_datashare *h, php_http_client_t *client); -typedef STATUS (*php_http_client_datashare_setopt_func_t)(struct php_http_client_datashare *h, php_http_client_datashare_setopt_opt_t opt, void *arg); - -typedef struct php_http_client_datashare_ops { - php_resource_factory_ops_t *rsrc; - php_http_client_datashare_init_func_t init; - php_http_client_datashare_copy_func_t copy; - php_http_client_datashare_dtor_func_t dtor; - php_http_client_datashare_reset_func_t reset; - php_http_client_datashare_attach_func_t attach; - php_http_client_datashare_detach_func_t detach; - php_http_client_datashare_setopt_func_t setopt; - php_http_new_t create_object; - zend_class_entry *(*class_entry)(void); -} php_http_client_datashare_ops_t; - -typedef struct php_http_client_datashare { - void *ctx; - php_resource_factory_t *rf; - php_http_client_datashare_ops_t *ops; - zend_llist clients; -#ifdef ZTS - void ***ts; -#endif -} php_http_client_datashare_t; - -PHP_MINIT_FUNCTION(http_client_datashare); - -PHP_HTTP_API php_http_client_datashare_t *php_http_client_datashare_init(php_http_client_datashare_t *h, php_http_client_datashare_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); -PHP_HTTP_API php_http_client_datashare_t *php_http_client_datashare_copy(php_http_client_datashare_t *from, php_http_client_datashare_t *to); -PHP_HTTP_API void php_http_client_datashare_dtor(php_http_client_datashare_t *h); -PHP_HTTP_API void php_http_client_datashare_free(php_http_client_datashare_t **h); -PHP_HTTP_API STATUS php_http_client_datashare_attach(php_http_client_datashare_t *h, zval *client); -PHP_HTTP_API STATUS php_http_client_datashare_detach(php_http_client_datashare_t *h, zval *client); -PHP_HTTP_API STATUS php_http_client_datashare_setopt(php_http_client_datashare_t *h, php_http_client_datashare_setopt_opt_t opt, void *arg); -PHP_HTTP_API void php_http_client_datashare_reset(php_http_client_datashare_t *h); - -typedef struct php_http_client_datashare_object { - zend_object zo; - php_http_client_datashare_t *share; -} php_http_client_datashare_object_t; - -zend_object_value php_http_client_datashare_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_client_datashare_object_new_ex(zend_class_entry *ce, php_http_client_datashare_t *share, php_http_client_datashare_object_t **ptr TSRMLS_DC); -void php_http_client_datashare_object_free(void *object TSRMLS_DC); - -zend_class_entry *php_http_client_datashare_get_class_entry(); -zend_object_handlers *php_http_client_datashare_get_object_handlers(void); - -PHP_METHOD(HttpClientDataShare, __destruct); -PHP_METHOD(HttpClientDataShare, count); -PHP_METHOD(HttpClientDataShare, attach); -PHP_METHOD(HttpClientDataShare, detach); -PHP_METHOD(HttpClientDataShare, reset); - -#endif /* PHP_HTTP_CLIENT_DATASHARE_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_factory.c b/php_http_client_factory.c deleted file mode 100644 index 318c63b..0000000 --- a/php_http_client_factory.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" - -#include - -/* - * array of name => php_http_client_factory_driver_t* - */ -static HashTable php_http_client_factory_drivers; - -PHP_HTTP_API STATUS php_http_client_factory_add_driver(const char *name_str, size_t name_len, php_http_client_factory_driver_t *driver) -{ - return zend_hash_add(&php_http_client_factory_drivers, name_str, name_len + 1, (void *) driver, sizeof(php_http_client_factory_driver_t), NULL); -} - -PHP_HTTP_API STATUS php_http_client_factory_get_driver(const char *name_str, size_t name_len, php_http_client_factory_driver_t *driver) -{ - php_http_client_factory_driver_t *tmp; - - if (SUCCESS == zend_hash_find(&php_http_client_factory_drivers, name_str, name_len + 1, (void *) &tmp)) { - *driver = *tmp; - return SUCCESS; - } - return FAILURE; -} - -static zend_class_entry *php_http_client_factory_find_class_entry(zval *this_ptr, const char *for_str, size_t for_len TSRMLS_DC) -{ - /* stupid non-const api */ - zval *cn = zend_read_property(Z_OBJCE_P(getThis()), getThis(), for_str, for_len, 0 TSRMLS_CC); - - if (Z_TYPE_P(cn) == IS_STRING && Z_STRLEN_P(cn)) { - return zend_fetch_class(Z_STRVAL_P(cn), Z_STRLEN_P(cn), 0 TSRMLS_CC); - } - - return NULL; -} - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientFactory, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientFactory, method, 0) -#define PHP_HTTP_REQUEST_FACTORY_ME(method, visibility) PHP_ME(HttpClientFactory, method, PHP_HTTP_ARGS(HttpClientFactory, method), visibility) -#define PHP_HTTP_REQUEST_FACTORY_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClientFactory, method)) -#define PHP_HTTP_REQUEST_FACTORY_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClientFactory_##al), PHP_HTTP_ARGS(HttpClientFactory, al), vis) - -PHP_HTTP_BEGIN_ARGS(__construct, 0) - PHP_HTTP_ARG_VAL(options, 0) -PHP_HTTP_END_ARGS; -PHP_HTTP_BEGIN_ARGS(createClient, 0) - PHP_HTTP_ARG_ARR(options, 1, 0) -PHP_HTTP_END_ARGS; -PHP_HTTP_BEGIN_ARGS(createPool, 0) - PHP_HTTP_ARG_OBJ(http\\Client, client1, 1) - PHP_HTTP_ARG_OBJ(http\\Client, client2, 1) - PHP_HTTP_ARG_OBJ(http\\Client, clientN, 1) -PHP_HTTP_END_ARGS; -PHP_HTTP_BEGIN_ARGS(createDataShare, 0) - PHP_HTTP_ARG_OBJ(http\\Client, client1, 1) - PHP_HTTP_ARG_OBJ(http\\Client, client2, 1) - PHP_HTTP_ARG_OBJ(http\\Client, clientN, 1) -PHP_HTTP_END_ARGS; -PHP_HTTP_EMPTY_ARGS(getDriver); -PHP_HTTP_EMPTY_ARGS(getAvailableDrivers); - -static zend_class_entry *php_http_client_factory_class_entry; - -zend_class_entry *php_http_client_factory_get_class_entry(void) -{ - return php_http_client_factory_class_entry; -} - -static zend_function_entry php_http_client_factory_method_entry[] = { - PHP_HTTP_REQUEST_FACTORY_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - PHP_HTTP_REQUEST_FACTORY_ME(createClient, ZEND_ACC_PUBLIC) - PHP_HTTP_REQUEST_FACTORY_ME(createPool, ZEND_ACC_PUBLIC) - PHP_HTTP_REQUEST_FACTORY_ME(createDataShare, ZEND_ACC_PUBLIC) - PHP_HTTP_REQUEST_FACTORY_ME(getDriver, ZEND_ACC_PUBLIC) - PHP_HTTP_REQUEST_FACTORY_ME(getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - - EMPTY_FUNCTION_ENTRY -}; - -PHP_METHOD(HttpClientFactory, __construct) -{ - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - HashTable *options = NULL; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|h", &options)) { - if (options) { - zval **val; - HashPosition pos; - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - - FOREACH_HASH_KEYVAL(pos, options, key, val) { - if (key.type == HASH_KEY_IS_STRING) { - zval *newval = php_http_zsep(1, Z_TYPE_PP(val), *val); - zend_update_property(php_http_client_factory_class_entry, getThis(), key.str, key.len - 1, newval TSRMLS_CC); - zval_ptr_dtor(&newval); - } - } - } - } - } end_error_handling(); -} - -PHP_METHOD(HttpClientFactory, createClient) -{ - zval *options = NULL; - - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &options)) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - zval *zdriver; - zend_object_value ov; - zend_class_entry *class_entry = NULL; - php_http_client_t *req = NULL; - php_http_client_factory_driver_t driver; - - zdriver = zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC); - - if ((IS_STRING == Z_TYPE_P(zdriver)) && (SUCCESS == php_http_client_factory_get_driver(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver), &driver)) && driver.client_ops) { - zval *phi = php_http_zsep(1, IS_STRING, zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("persistentHandleId"), 0 TSRMLS_CC)); - php_resource_factory_t *rf = NULL; - - if (Z_STRLEN_P(phi)) { - char *name_str; - size_t name_len; - php_persistent_handle_factory_t *pf; - - name_len = spprintf(&name_str, 0, "http_client.%s", Z_STRVAL_P(zdriver)); - - if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi), NULL, NULL TSRMLS_CC))) { - rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon); - } - - efree(name_str); - } - - req = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC); - if (req) { - if (!(class_entry = php_http_client_factory_find_class_entry(getThis(), ZEND_STRL("clientClass") TSRMLS_CC))) { - class_entry = driver.client_ops->class_entry(); - } - - if (SUCCESS == php_http_new(&ov, class_entry, driver.client_ops->create_object, driver.client_ops->class_entry(), req, NULL TSRMLS_CC)) { - ZVAL_OBJVAL(return_value, ov, 0); - zend_call_method(&return_value, Z_OBJCE_P(return_value), NULL, ZEND_STRL("__construct"), NULL, !!options, options, NULL TSRMLS_CC); - } else { - php_http_client_free(&req); - } - } - - zval_ptr_dtor(&phi); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "clients are not supported by this driver"); - } - } end_error_handling(); - } - } end_error_handling(); -} - -PHP_METHOD(HttpClientFactory, createPool) -{ - int argc = 0; - zval ***argv = NULL; - - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &argv, &argc)) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - int i; - zval *zdriver; - zend_object_value ov; - zend_class_entry *class_entry = NULL; - php_http_client_pool_t *pool = NULL; - php_http_client_factory_driver_t driver; - - zdriver = zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC); - if ((IS_STRING == Z_TYPE_P(zdriver)) && (SUCCESS == php_http_client_factory_get_driver(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver), &driver)) && driver.client_pool_ops) { - zval *phi = php_http_zsep(1, IS_STRING, zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("persistentHandleId"), 0 TSRMLS_CC)); - php_resource_factory_t *rf = NULL; - - if (Z_STRLEN_P(phi)) { - char *name_str; - size_t name_len; - php_persistent_handle_factory_t *pf; - - name_len = spprintf(&name_str, 0, "http_client_pool.%s", Z_STRVAL_P(zdriver)); - - if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi), NULL, NULL TSRMLS_CC))) { - rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon); - } - - efree(name_str); - } - - pool = php_http_client_pool_init(NULL, driver.client_pool_ops, rf, NULL TSRMLS_CC); - if (pool) { - if (!(class_entry = php_http_client_factory_find_class_entry(getThis(), ZEND_STRL("clientPoolClass") TSRMLS_CC))) { - class_entry = driver.client_pool_ops->class_entry(); - } - - if (SUCCESS == php_http_new(&ov, class_entry, driver.client_pool_ops->create_object, driver.client_pool_ops->class_entry(), pool, NULL TSRMLS_CC)) { - ZVAL_OBJVAL(return_value, ov, 0); - for (i = 0; i < argc; ++i) { - if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), php_http_client_get_class_entry() TSRMLS_CC)) { - php_http_client_pool_attach(pool, *(argv[i])); - } - } - } else { - php_http_client_pool_free(&pool); - } - } - - zval_ptr_dtor(&phi); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "pools are not supported by this driver"); - } - } end_error_handling(); - - if (argv) { - efree(argv); - } - } - } end_error_handling(); -} - -PHP_METHOD(HttpClientFactory, createDataShare) -{ - int argc = 0; - zval ***argv = NULL; - - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &argv, &argc)) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - int i; - zval *zdriver; - zend_object_value ov; - zend_class_entry *class_entry; - php_http_client_datashare_t *share = NULL; - php_http_client_factory_driver_t driver; - - zdriver = zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC); - if ((IS_STRING == Z_TYPE_P(zdriver)) && (SUCCESS == php_http_client_factory_get_driver(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver), &driver)) && driver.client_datashare_ops) { - zval *phi = php_http_zsep(1, IS_STRING, zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("persistentHandleId"), 0 TSRMLS_CC)); - php_resource_factory_t *rf = NULL; - - if (Z_STRLEN_P(phi)) { - char *name_str; - size_t name_len; - php_persistent_handle_factory_t *pf; - - name_len = spprintf(&name_str, 0, "http_client_datashare.%s", Z_STRVAL_P(zdriver)); - - if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi), NULL, NULL TSRMLS_CC))) { - rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon); - } - - efree(name_str); - } - - share = php_http_client_datashare_init(NULL, driver.client_datashare_ops, rf, NULL TSRMLS_CC); - if (share) { - if (!(class_entry = php_http_client_factory_find_class_entry(getThis(), ZEND_STRL("clientDataShareClass") TSRMLS_CC))) { - class_entry = driver.client_datashare_ops->class_entry(); - } - - if (SUCCESS == php_http_new(&ov, class_entry, driver.client_datashare_ops->create_object, driver.client_datashare_ops->class_entry(), share, NULL TSRMLS_CC)) { - ZVAL_OBJVAL(return_value, ov, 0); - for (i = 0; i < argc; ++i) { - if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), php_http_client_get_class_entry() TSRMLS_CC)) { - php_http_client_datashare_attach(share, *(argv[i])); - } - } - } else { - php_http_client_datashare_free(&share); - } - } - - zval_ptr_dtor(&phi); - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "datashares are not supported by this driver"); - } - } end_error_handling(); - if (argv) { - efree(argv); - } - } - } end_error_handling(); -} - -PHP_METHOD(HttpClientFactory, getDriver) -{ - if (SUCCESS == zend_parse_parameters_none()) { - RETURN_PROP(php_http_client_factory_class_entry, "driver"); - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientFactory, getAvailableDrivers) -{ - if (SUCCESS == zend_parse_parameters_none()) { - HashPosition pos; - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - - array_init(return_value); - FOREACH_HASH_KEY(pos, &php_http_client_factory_drivers, key) { - add_next_index_stringl(return_value, key.str, key.len - 1, 1); - } - return; - } - RETURN_FALSE; -} - -PHP_MINIT_FUNCTION(http_client_factory) -{ - zend_hash_init(&php_http_client_factory_drivers, 0, NULL, NULL, 1); - - PHP_HTTP_REGISTER_CLASS(http\\Client, Factory, http_client_factory, php_http_object_get_class_entry(), 0); - php_http_client_factory_class_entry->create_object = php_http_client_factory_new; - - zend_declare_property_stringl(php_http_client_factory_class_entry, ZEND_STRL("driver"), ZEND_STRL("curl"), ZEND_ACC_PROTECTED TSRMLS_CC); - zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("persistentHandleId"), ZEND_ACC_PROTECTED TSRMLS_CC); - zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("clientClass"), ZEND_ACC_PROTECTED TSRMLS_CC); - zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("clientPoolClass"), ZEND_ACC_PROTECTED TSRMLS_CC); - zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("clientDataShareClass"), ZEND_ACC_PROTECTED TSRMLS_CC); - - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(http_client_factory) -{ - zend_hash_destroy(&php_http_client_factory_drivers); - - return SUCCESS; -} - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_factory.h b/php_http_client_factory.h deleted file mode 100644 index ffa4f8e..0000000 --- a/php_http_client_factory.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_REQUEST_FACTORY_H -#define PHP_HTTP_REQUEST_FACTORY_H - -#include "php_http_client.h" -#include "php_http_client_pool.h" -#include "php_http_client_datashare.h" - -typedef struct php_http_client_factory_driver { - php_http_client_ops_t *client_ops; - php_http_client_pool_ops_t *client_pool_ops; - php_http_client_datashare_ops_t *client_datashare_ops; -} php_http_client_factory_driver_t; - -PHP_HTTP_API STATUS php_http_client_factory_add_driver(const char *name_str, size_t name_len, php_http_client_factory_driver_t *driver); -PHP_HTTP_API STATUS php_http_client_factory_get_driver(const char *name_str, size_t name_len, php_http_client_factory_driver_t *driver); - -zend_class_entry *php_http_client_factory_get_class_entry(void); - -#define php_http_client_factory_new php_http_object_new - -PHP_METHOD(HttpClientFactory, __construct); -PHP_METHOD(HttpClientFactory, createClient); -PHP_METHOD(HttpClientFactory, createPool); -PHP_METHOD(HttpClientFactory, createDataShare); -PHP_METHOD(HttpClientFactory, getGlobalDataShareInstance); -PHP_METHOD(HttpClientFactory, getDriver); -PHP_METHOD(HttpClientFactory, getAvailableDrivers); - -extern PHP_MINIT_FUNCTION(http_client_factory); -extern PHP_MSHUTDOWN_FUNCTION(http_client_factory); - -#endif /* PHP_HTTP_REQUEST_FACTORY_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_interface.c b/php_http_client_interface.c deleted file mode 100644 index 3040e76..0000000 --- a/php_http_client_interface.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" -#include "php_http_client.h" - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClient, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClient, method, 0) -#define PHP_HTTP_CLIENT_ME(method) PHP_ABSTRACT_ME(HttpClient, method, PHP_HTTP_ARGS(HttpClient, method)) - -PHP_HTTP_BEGIN_ARGS(send, 1) - PHP_HTTP_ARG_VAL(request, 0) -PHP_HTTP_END_ARGS; - -static zend_class_entry *php_http_client_interface_class_entry; - -zend_class_entry *php_http_client_interface_get_class_entry(void) -{ - return php_http_client_interface_class_entry; -} - -zend_function_entry php_http_client_interface_method_entry[] = { - PHP_HTTP_CLIENT_ME(send) - {NULL, NULL, NULL} -}; - -PHP_MINIT_FUNCTION(http_client_interface) -{ - PHP_HTTP_REGISTER_INTERFACE(http, Client, http_client_interface, ZEND_ACC_INTERFACE); - - return SUCCESS; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_interface.h b/php_http_client_interface.h deleted file mode 100644 index 2bbd736..0000000 --- a/php_http_client_interface.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_CLIENT_INTERFACE_H - -zend_class_entry *php_http_client_interface_get_class_entry(void); - -PHP_MINIT_FUNCTION(http_client_interface); - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_pool.c b/php_http_client_pool.c deleted file mode 100644 index 3e6b6f9..0000000 --- a/php_http_client_pool.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" - -PHP_HTTP_API php_http_client_pool_t *php_http_client_pool_init(php_http_client_pool_t *h, php_http_client_pool_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC) -{ - php_http_client_pool_t *free_h = NULL; - - if (!h) { - free_h = h = emalloc(sizeof(*h)); - } - memset(h, 0, sizeof(*h)); - - h->ops = ops; - if (rf) { - h->rf = rf; - } else if (ops->rsrc) { - h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL); - } - zend_llist_init(&h->clients.attached, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0); - zend_llist_init(&h->clients.finished, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0); - TSRMLS_SET_CTX(h->ts); - - if (h->ops->init) { - if (!(h = h->ops->init(h, init_arg))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Could not initialize request pool"); - if (free_h) { - efree(h); - } - } - } - - return h; -} - -PHP_HTTP_API php_http_client_pool_t *php_http_client_pool_copy(php_http_client_pool_t *from, php_http_client_pool_t *to) -{ - if (from->ops->copy) { - return from->ops->copy(from, to); - } - - return NULL; -} - -PHP_HTTP_API void php_http_client_pool_dtor(php_http_client_pool_t *h) -{ - if (h->ops->dtor) { - h->ops->dtor(h); - } - - zend_llist_clean(&h->clients.finished); - zend_llist_clean(&h->clients.attached); - - php_resource_factory_free(&h->rf); -} - -PHP_HTTP_API void php_http_client_pool_free(php_http_client_pool_t **h) { - if (*h) { - php_http_client_pool_dtor(*h); - efree(*h); - *h = NULL; - } -} - -PHP_HTTP_API STATUS php_http_client_pool_attach(php_http_client_pool_t *h, zval *client) -{ - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (h->ops->attach) { - zval *zreq = NULL; - php_http_client_object_t *obj; - php_http_message_object_t *msg_obj; - - if (SUCCESS != php_http_client_object_handle_request(client, &zreq TSRMLS_CC)) { - return FAILURE; - } - - obj = zend_object_store_get_object(client TSRMLS_CC); - msg_obj = zend_object_store_get_object(zreq TSRMLS_CC); - - if (SUCCESS == h->ops->attach(h, obj->client, msg_obj->message)) { - Z_ADDREF_P(client); - zend_llist_add_element(&h->clients.attached, &client); - return SUCCESS; - } - } - - return FAILURE; -} - -static int php_http_client_pool_compare_handles(void *h1, void *h2) -{ - return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2)); -} - - -PHP_HTTP_API STATUS php_http_client_pool_detach(php_http_client_pool_t *h, zval *client) -{ - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (h->ops->detach) { - php_http_client_object_t *obj = zend_object_store_get_object(client TSRMLS_CC); - - if (SUCCESS == h->ops->detach(h, obj->client)) { - zend_llist_del_element(&h->clients.finished, client, php_http_client_pool_compare_handles); - zend_llist_del_element(&h->clients.attached, client, php_http_client_pool_compare_handles); - return SUCCESS; - } - } - - return FAILURE; -} - -PHP_HTTP_API STATUS php_http_client_pool_wait(php_http_client_pool_t *h, struct timeval *custom_timeout) -{ - if (h->ops->wait) { - return h->ops->wait(h, custom_timeout); - } - - return FAILURE; -} - -PHP_HTTP_API int php_http_client_pool_once(php_http_client_pool_t *h) -{ - if (h->ops->once) { - return h->ops->once(h); - } - - return FAILURE; -} - -PHP_HTTP_API STATUS php_http_client_pool_exec(php_http_client_pool_t *h) -{ - if (h->ops->exec) { - return h->ops->exec(h); - } - - return FAILURE; -} - -static void detach(void *r, void *h TSRMLS_DC) -{ - ((php_http_client_pool_t *) h)->ops->detach(h, ((php_http_client_object_t *) zend_object_store_get_object(*((zval **) r) TSRMLS_CC))->client); -} - -PHP_HTTP_API void php_http_client_pool_reset(php_http_client_pool_t *h) -{ - if (h->ops->reset) { - h->ops->reset(h); - } else if (h->ops->detach) { - TSRMLS_FETCH_FROM_CTX(h->ts); - - zend_llist_apply_with_argument(&h->clients.attached, detach, h TSRMLS_CC); - } - - zend_llist_clean(&h->clients.attached); - zend_llist_clean(&h->clients.finished); -} - -PHP_HTTP_API STATUS php_http_client_pool_setopt(php_http_client_pool_t *h, php_http_client_pool_setopt_opt_t opt, void *arg) -{ - if (h->ops->setopt) { - return h->ops->setopt(h, opt, arg); - } - - return FAILURE; -} - -PHP_HTTP_API void php_http_client_pool_requests(php_http_client_pool_t *h, zval ***attached, zval ***finished) -{ - zval **handle; - int i, count; - - if (attached) { - if ((count = zend_llist_count(&h->clients.attached))) { - *attached = ecalloc(count + 1 /* terminating NULL */, sizeof(zval *)); - - for (i = 0, handle = zend_llist_get_first(&h->clients.attached); handle; handle = zend_llist_get_next(&h->clients.attached)) { - Z_ADDREF_PP(handle); - (*attached)[i++] = *handle; - } - } else { - *attached = NULL; - } - } - - if (finished) { - if ((count = zend_llist_count(&h->clients.finished))) { - *finished = ecalloc(count + 1 /* terminating NULL */, sizeof(zval *)); - - for (i = 0, handle = zend_llist_get_first(&h->clients.finished); handle; handle = zend_llist_get_next(&h->clients.finished)) { - Z_ADDREF_PP(handle); - (*finished)[i++] = *handle; - } - } else { - *finished = NULL; - } - } -} - -/*#*/ - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientPool, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientPool, method, 0) -#define PHP_HTTP_CLIENT_POOL_ME(method, visibility) PHP_ME(HttpClientPool, method, PHP_HTTP_ARGS(HttpClientPool, method), visibility) - -PHP_HTTP_EMPTY_ARGS(__destruct); -PHP_HTTP_EMPTY_ARGS(reset); - -PHP_HTTP_BEGIN_ARGS(attach, 1) - PHP_HTTP_ARG_OBJ(http\\Client\\AbstractClient, request, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_BEGIN_ARGS(detach, 1) - PHP_HTTP_ARG_OBJ(http\\Client\\AbstractClient, request, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(send); -PHP_HTTP_EMPTY_ARGS(once); -PHP_HTTP_BEGIN_ARGS(wait, 0) - PHP_HTTP_ARG_VAL(timeout, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_EMPTY_ARGS(valid); -PHP_HTTP_EMPTY_ARGS(current); -PHP_HTTP_EMPTY_ARGS(key); -PHP_HTTP_EMPTY_ARGS(next); -PHP_HTTP_EMPTY_ARGS(rewind); - -PHP_HTTP_EMPTY_ARGS(count); - -PHP_HTTP_EMPTY_ARGS(getAttached); -PHP_HTTP_EMPTY_ARGS(getFinished); - -PHP_HTTP_BEGIN_ARGS(enablePipelining, 0) - PHP_HTTP_ARG_VAL(enable, 0) -PHP_HTTP_END_ARGS; - -PHP_HTTP_BEGIN_ARGS(enableEvents, 0) - PHP_HTTP_ARG_VAL(enable, 0) -PHP_HTTP_END_ARGS; - -static zend_class_entry *php_http_client_pool_class_entry; - -zend_class_entry *php_http_client_pool_get_class_entry(void) -{ - return php_http_client_pool_class_entry; -} - -static zend_function_entry php_http_client_pool_method_entry[] = { - PHP_HTTP_CLIENT_POOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR) - PHP_HTTP_CLIENT_POOL_ME(attach, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(detach, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(send, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(reset, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_POOL_ME(once, ZEND_ACC_PROTECTED) - PHP_HTTP_CLIENT_POOL_ME(wait, ZEND_ACC_PROTECTED) - - /* implements Iterator */ - PHP_HTTP_CLIENT_POOL_ME(valid, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(current, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(key, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(next, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(rewind, ZEND_ACC_PUBLIC) - - /* implmenents Countable */ - PHP_HTTP_CLIENT_POOL_ME(count, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_POOL_ME(getAttached, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(getFinished, ZEND_ACC_PUBLIC) - - PHP_HTTP_CLIENT_POOL_ME(enablePipelining, ZEND_ACC_PUBLIC) - PHP_HTTP_CLIENT_POOL_ME(enableEvents, ZEND_ACC_PUBLIC) - - EMPTY_FUNCTION_ENTRY -}; - -static zend_object_handlers php_http_client_pool_object_handlers; - -extern zend_object_handlers *php_http_client_pool_get_object_handlers(void) -{ - return &php_http_client_pool_object_handlers; -} - -static php_http_client_pool_ops_t php_http_client_pool_user_ops = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - (php_http_new_t) php_http_client_pool_object_new_ex, - php_http_client_pool_get_class_entry -}; - -zend_object_value php_http_client_pool_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return php_http_client_pool_object_new_ex(ce, NULL, NULL TSRMLS_CC); -} - -zend_object_value php_http_client_pool_object_new_ex(zend_class_entry *ce, php_http_client_pool_t *p, php_http_client_pool_object_t **ptr TSRMLS_DC) -{ - zend_object_value ov; - php_http_client_pool_object_t *o; - - o = ecalloc(1, sizeof(php_http_client_pool_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (!(o->pool = p)) { - o->pool = php_http_client_pool_init(NULL, &php_http_client_pool_user_ops, NULL, NULL TSRMLS_CC); - } - - if (ptr) { - *ptr = o; - } - - ov.handle = zend_objects_store_put(o, NULL, php_http_client_pool_object_free, NULL TSRMLS_CC); - ov.handlers = &php_http_client_pool_object_handlers; - - return ov; -} - -void php_http_client_pool_object_free(void *object TSRMLS_DC) -{ - php_http_client_pool_object_t *o = (php_http_client_pool_object_t *) object; - - php_http_client_pool_free(&o->pool); - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(o); -} - -static void php_http_client_pool_object_llist2array(zval **req, zval *array TSRMLS_DC) -{ - Z_ADDREF_P(*req); - add_next_index_zval(array, *req); -} - -PHP_METHOD(HttpClientPool, __destruct) -{ - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - if (SUCCESS != zend_parse_parameters_none()) { - ; /* we always want to clean up */ - } - /* FIXME: move to php_http_client_pool_dtor */ - php_http_client_pool_reset(obj->pool); -} - -PHP_METHOD(HttpClientPool, reset) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - obj->iterator.pos = 0; - php_http_client_pool_reset(obj->pool); - } - RETVAL_ZVAL(getThis(), 1, 0); -} - -PHP_METHOD(HttpClientPool, attach) -{ - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - zval *request; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_get_class_entry())) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool->clients.attached)) { - php_http_error(HE_THROW, PHP_HTTP_E_CLIENT_POOL, "Cannot attach to the HttpClientPool while the iterator is active"); - } else { - php_http_client_pool_attach(obj->pool, request); - } - } end_error_handling(); - } - } end_error_handling(); - - RETVAL_ZVAL(getThis(), 1, 0); -} - -PHP_METHOD(HttpClientPool, detach) -{ - RETVAL_FALSE; - - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - zval *request; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_get_class_entry())) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - obj->iterator.pos = -1; - php_http_client_pool_detach(obj->pool, request); - } end_error_handling(); - } - } end_error_handling(); - - RETVAL_ZVAL(getThis(), 1, 0); -} - -PHP_METHOD(HttpClientPool, send) -{ - RETVAL_FALSE; - - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - if (SUCCESS == zend_parse_parameters_none()) { - with_error_handling(EH_THROW, php_http_exception_get_class_entry()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - php_http_client_pool_exec(obj->pool); - } end_error_handling(); - } - } end_error_handling(); - - RETVAL_ZVAL(getThis(), 1, 0); -} - -PHP_METHOD(HttpClientPool, once) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - if (0 < php_http_client_pool_once(obj->pool)) { - RETURN_TRUE; - } - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, wait) -{ - double timeout = 0; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) { - struct timeval timeout_val; - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - timeout_val.tv_sec = (time_t) timeout; - timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC; - - RETURN_SUCCESS(php_http_client_pool_wait(obj->pool, timeout > 0 ? &timeout_val : NULL)); - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, valid) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool->clients.attached)); - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, current) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - if (obj->iterator.pos < zend_llist_count(&obj->pool->clients.attached)) { - long pos = 0; - zval **current = NULL; - zend_llist_position lpos; - - for ( current = zend_llist_get_first_ex(&obj->pool->clients.attached, &lpos); - current && obj->iterator.pos != pos++; - current = zend_llist_get_next_ex(&obj->pool->clients.attached, &lpos)); - if (current) { - RETURN_OBJECT(*current, 1); - } - } - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, key) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - RETURN_LONG(obj->iterator.pos); - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, next) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - ++obj->iterator.pos; - } -} - -PHP_METHOD(HttpClientPool, rewind) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - obj->iterator.pos = 0; - } -} - -PHP_METHOD(HttpClientPool, count) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - RETURN_LONG((long) zend_llist_count(&obj->pool->clients.attached)); - } -} - -PHP_METHOD(HttpClientPool, getAttached) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - array_init(return_value); - zend_llist_apply_with_argument(&obj->pool->clients.attached, - (llist_apply_with_arg_func_t) php_http_client_pool_object_llist2array, - return_value TSRMLS_CC); - return; - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, getFinished) -{ - if (SUCCESS == zend_parse_parameters_none()) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - array_init(return_value); - zend_llist_apply_with_argument(&obj->pool->clients.finished, - (llist_apply_with_arg_func_t) php_http_client_pool_object_llist2array, - return_value TSRMLS_CC); - return; - } - RETURN_FALSE; -} - -PHP_METHOD(HttpClientPool, enablePipelining) -{ - zend_bool enable = 1; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - php_http_client_pool_setopt(obj->pool, PHP_HTTP_CLIENT_POOL_OPT_ENABLE_PIPELINING, &enable); - } - RETVAL_ZVAL(getThis(), 1, 0); -} - -PHP_METHOD(HttpClientPool, enableEvents) -{ - zend_bool enable = 1; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) { - php_http_client_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - - php_http_client_pool_setopt(obj->pool, PHP_HTTP_CLIENT_POOL_OPT_USE_EVENTS, &enable); - } - RETVAL_ZVAL(getThis(), 1, 0); -} - -PHP_MINIT_FUNCTION(http_client_pool) -{ - PHP_HTTP_REGISTER_CLASS(http\\Client\\Pool, AbstractPool, http_client_pool, php_http_object_get_class_entry(), ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); - php_http_client_pool_class_entry->create_object = php_http_client_pool_object_new; - memcpy(&php_http_client_pool_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - php_http_client_pool_object_handlers.clone_obj = NULL; - - zend_class_implements(php_http_client_pool_class_entry TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator); - - return SUCCESS; -} - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_pool.h b/php_http_client_pool.h deleted file mode 100644 index 17bfe13..0000000 --- a/php_http_client_pool.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_CLIENT_POOL_H -#define PHP_HTTP_CLIENT_POOL_H - -typedef enum php_http_client_pool_setopt_opt { - PHP_HTTP_CLIENT_POOL_OPT_ENABLE_PIPELINING, - PHP_HTTP_CLIENT_POOL_OPT_USE_EVENTS, -} php_http_client_pool_setopt_opt_t; - -typedef struct php_http_client_pool *(*php_http_client_pool_init_func_t)(struct php_http_client_pool *p, void *arg); -typedef struct php_http_client_pool *(*php_http_client_pool_copy_func_t)(struct php_http_client_pool *from, struct php_http_client_pool *to); -typedef void (*php_http_client_pool_dtor_func_t)(struct php_http_client_pool *p); -typedef void (*php_http_client_pool_reset_func_t)(struct php_http_client_pool *p); -typedef STATUS (*php_http_client_pool_exec_func_t)(struct php_http_client_pool *p); -typedef STATUS (*php_http_client_pool_wait_func_t)(struct php_http_client_pool *p, struct timeval *custom_timeout); -typedef int (*php_http_client_pool_once_func_t)(struct php_http_client_pool *p); -typedef STATUS (*php_http_client_pool_attach_func_t)(struct php_http_client_pool *p, php_http_client_t *r, php_http_message_t *msg); -typedef STATUS (*php_http_client_pool_detach_func_t)(struct php_http_client_pool *p, php_http_client_t *r); -typedef STATUS (*php_http_client_pool_setopt_func_t)(struct php_http_client_pool *p, php_http_client_pool_setopt_opt_t opt, void *arg); - -typedef struct php_http_client_pool_ops { - php_resource_factory_ops_t *rsrc; - php_http_client_pool_init_func_t init; - php_http_client_pool_copy_func_t copy; - php_http_client_pool_dtor_func_t dtor; - php_http_client_pool_reset_func_t reset; - php_http_client_pool_exec_func_t exec; - php_http_client_pool_wait_func_t wait; - php_http_client_pool_once_func_t once; - php_http_client_pool_attach_func_t attach; - php_http_client_pool_detach_func_t detach; - php_http_client_pool_setopt_func_t setopt; - php_http_new_t create_object; - zend_class_entry *(*class_entry)(void); -} php_http_client_pool_ops_t; - -typedef struct php_http_client_pool { - void *ctx; - php_resource_factory_t *rf; - php_http_client_pool_ops_t *ops; - - struct { - php_http_client_t *master; - zend_llist attached; - zend_llist finished; - } clients; - -#ifdef ZTS - void ***ts; -#endif -} php_http_client_pool_t; - -PHP_HTTP_API php_http_client_pool_t *php_http_client_pool_init(php_http_client_pool_t *pool, php_http_client_pool_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); -PHP_HTTP_API php_http_client_pool_t *php_http_client_pool_copy(php_http_client_pool_t *from, php_http_client_pool_t *to); -PHP_HTTP_API void php_http_client_pool_dtor(php_http_client_pool_t *pool); -PHP_HTTP_API void php_http_client_pool_free(php_http_client_pool_t **pool); -PHP_HTTP_API void php_http_client_pool_reset(php_http_client_pool_t *pool); -PHP_HTTP_API STATUS php_http_client_pool_exec(php_http_client_pool_t *pool); -PHP_HTTP_API STATUS php_http_client_pool_wait(php_http_client_pool_t *pool, struct timeval *custom_timeout); -PHP_HTTP_API STATUS php_http_client_pool_once(php_http_client_pool_t *pool); -PHP_HTTP_API STATUS php_http_client_pool_attach(php_http_client_pool_t *pool, zval *request); -PHP_HTTP_API STATUS php_http_client_pool_detach(php_http_client_pool_t *pool, zval *request); -PHP_HTTP_API STATUS php_http_client_pool_setopt(php_http_client_pool_t *pool, php_http_client_pool_setopt_opt_t opt, void *arg); -PHP_HTTP_API void php_http_client_pool_requests(php_http_client_pool_t *h, zval ***attached, zval ***finished); - -typedef struct php_http_client_pool_object { - zend_object zo; - php_http_client_pool_t *pool; - zend_object_value client; - struct { - long pos; - } iterator; -} php_http_client_pool_object_t; - -zend_object_value php_http_client_pool_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_client_pool_object_new_ex(zend_class_entry *ce, php_http_client_pool_t *p, php_http_client_pool_object_t **ptr TSRMLS_DC); -void php_http_client_pool_object_free(void *object TSRMLS_DC); - -zend_class_entry *php_http_client_pool_get_class_entry(void); -zend_object_handlers *php_http_client_pool_get_object_handlers(void); - -PHP_METHOD(HttpClientPool, __destruct); -PHP_METHOD(HttpClientPool, attach); -PHP_METHOD(HttpClientPool, detach); -PHP_METHOD(HttpClientPool, send); -PHP_METHOD(HttpClientPool, reset); -PHP_METHOD(HttpClientPool, once); -PHP_METHOD(HttpClientPool, wait); -PHP_METHOD(HttpClientPool, valid); -PHP_METHOD(HttpClientPool, current); -PHP_METHOD(HttpClientPool, key); -PHP_METHOD(HttpClientPool, next); -PHP_METHOD(HttpClientPool, rewind); -PHP_METHOD(HttpClientPool, count); -PHP_METHOD(HttpClientPool, getAttached); -PHP_METHOD(HttpClientPool, getFinished); -PHP_METHOD(HttpClientPool, enablePipelining); -PHP_METHOD(HttpClientPool, enableEvents); - -PHP_MINIT_FUNCTION(http_client_pool); - -#endif /* PHP_HTTP_CLIENT_POOL_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_client_request.c b/php_http_client_request.c index 2a842b4..42117f9 100644 --- a/php_http_client_request.c +++ b/php_http_client_request.c @@ -12,6 +12,10 @@ #include "php_http_api.h" +void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC); +void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC); +void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC); + #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientRequest, method, 0, req_args) #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientRequest, method, 0) #define PHP_HTTP_CLIENT_REQUEST_ME(method, visibility) PHP_ME(HttpClientRequest, method, PHP_HTTP_ARGS(HttpClientRequest, method), visibility) diff --git a/php_http_client_response.c b/php_http_client_response.c index bf08389..5068856 100644 --- a/php_http_client_response.c +++ b/php_http_client_response.c @@ -12,18 +12,11 @@ #include "php_http_api.h" -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientResponse, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientResponse, method, 0) -#define PHP_HTTP_CLIENT_RESPONSE_ME(method, visibility) PHP_ME(HttpClientResponse, method, PHP_HTTP_ARGS(HttpClientResponse, method), visibility) -#define PHP_HTTP_CLIENT_RESPONSE_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClientResponse, method)) -#define PHP_HTTP_CLIENT_RESPONSE_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClientResponse_##al), PHP_HTTP_ARGS(HttpClientResponse, al), vis) - -PHP_HTTP_BEGIN_ARGS(getCookies, 0) - PHP_HTTP_ARG_VAL(flags, 0) - PHP_HTTP_ARG_VAL(allowed_extras, 0) -PHP_HTTP_END_ARGS; - -PHP_METHOD(HttpClientResponse, getCookies) +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getCookies, 0, 0, 0) + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, allowed_extras) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientResponse, getCookies) { long flags = 0; zval *allowed_extras_array = NULL; @@ -91,6 +84,32 @@ PHP_METHOD(HttpClientResponse, getCookies) RETURN_FALSE; } +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getTransferInfo, 0, 0, 0) + ZEND_ARG_INFO(0, element) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClientResponse, getTransferInfo) +{ + char *info_name = NULL; + int info_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) { + zval **infop, *info = zend_read_property(php_http_client_response_get_class_entry(), getThis(), ZEND_STRL("transferInfo"), 0 TSRMLS_CC); + + /* request completed? */ + if (Z_TYPE_P(info) == IS_ARRAY) { + if (info_len && info_name) { + if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(info), php_http_pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) { + RETURN_ZVAL(*infop, 1, 0); + } else { + php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Could not find transfer info named %s", info_name); + } + } else { + RETURN_ZVAL(info, 1, 0); + } + } + } + RETURN_FALSE; +} static zend_class_entry *php_http_client_response_class_entry; @@ -100,7 +119,8 @@ zend_class_entry *php_http_client_response_get_class_entry(void) } static zend_function_entry php_http_client_response_method_entry[] = { - PHP_HTTP_CLIENT_RESPONSE_ME(getCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientResponse, getCookies, ai_HttpClientResponse_getCookies, ZEND_ACC_PUBLIC) + PHP_ME(HttpClientResponse, getTransferInfo, ai_HttpClientResponse_getTransferInfo, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; diff --git a/php_http_client_response.h b/php_http_client_response.h index 4a304ed..7ff0ae5 100644 --- a/php_http_client_response.h +++ b/php_http_client_response.h @@ -15,8 +15,6 @@ zend_class_entry *php_http_client_response_get_class_entry(void); -PHP_METHOD(HttpClientResponse, getCookies); - PHP_MINIT_FUNCTION(http_client_response); #endif /* PHP_HTTP_CLIENT_RESPONSE_H */ diff --git a/php_http_curl.c b/php_http_curl.c index e9153b1..6b2bd33 100644 --- a/php_http_curl.c +++ b/php_http_curl.c @@ -91,12 +91,6 @@ static struct gcry_thread_cbs php_http_gnutls_tsl = { PHP_MINIT_FUNCTION(http_curl) { - php_http_client_factory_driver_t driver = { - php_http_curl_client_get_ops(), - php_http_curl_client_pool_get_ops(), - php_http_curl_client_datashare_get_ops() - }; - #ifdef PHP_HTTP_NEED_OPENSSL_TSL /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */ if (!CRYPTO_get_id_callback()) { @@ -120,10 +114,6 @@ PHP_MINIT_FUNCTION(http_curl) return FAILURE; } - if (SUCCESS != php_http_client_factory_add_driver(ZEND_STRL("curl"), &driver)) { - return FAILURE; - } - return SUCCESS; } diff --git a/php_http_curl_client.c b/php_http_curl_client.c deleted file mode 100644 index 174fa15..0000000 --- a/php_http_curl_client.c +++ /dev/null @@ -1,1521 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" - -/* resource_factory ops */ - -static void *php_http_curl_ctor(void *opaque, void *init_arg TSRMLS_DC) -{ - void *ch; - - if ((ch = curl_easy_init())) { - php_http_curl_client_get_storage(ch); - return ch; - } - return NULL; -} - -static void *php_http_curl_copy(void *opaque, void *handle TSRMLS_DC) -{ - void *ch; - - if ((ch = curl_easy_duphandle(handle))) { - curl_easy_reset(ch); - php_http_curl_client_get_storage(ch); - return ch; - } - return NULL; -} - -static void php_http_curl_dtor(void *opaque, void *handle TSRMLS_DC) -{ - php_http_curl_client_storage_t *st = php_http_curl_client_get_storage(handle); - - curl_easy_cleanup(handle); - - if (st) { - if (st->url) { - pefree(st->url, 1); - } - if (st->cookiestore) { - pefree(st->cookiestore, 1); - } - pefree(st, 1); - } -} - -/* callbacks */ - -static size_t php_http_curl_client_read_callback(void *data, size_t len, size_t n, void *ctx) -{ - php_http_message_body_t *body = ctx; - - if (body) { - TSRMLS_FETCH_FROM_CTX(body->ts); - return php_stream_read(php_http_message_body_stream(body), data, len * n); - } - return 0; -} - -static int php_http_curl_client_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow) -{ - php_http_client_t *h = ctx; - php_http_curl_client_t *curl = h->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - curl->progress.state.dl.total = dltotal; - curl->progress.state.dl.now = dlnow; - curl->progress.state.ul.total = ultotal; - curl->progress.state.ul.now = ulnow; - - php_http_client_progress_notify(&curl->progress TSRMLS_CC); - - return 0; -} - -static curlioerr php_http_curl_client_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx) -{ - php_http_message_body_t *body = ctx; - - if (cmd != CURLIOCMD_RESTARTREAD) { - return CURLIOE_UNKNOWNCMD; - } - - if (body) { - TSRMLS_FETCH_FROM_CTX(body->ts); - - if (SUCCESS == php_stream_rewind(php_http_message_body_stream(body))) { - return CURLIOE_OK; - } - } - - return CURLIOE_FAILRESTART; -} - -static int php_http_curl_client_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx) -{ - php_http_client_t *h = ctx; - php_http_curl_client_t *curl = h->ctx; - unsigned flags = 0; - TSRMLS_FETCH_FROM_CTX(h->ts); - - /* catch progress */ - switch (type) { - case CURLINFO_TEXT: - if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) { - curl->progress.state.info = "resolve"; - } else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) { - curl->progress.state.info = "connect"; - } else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) { - curl->progress.state.info = "connected"; - } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) { - curl->progress.state.info = "not disconnected"; - } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) { - curl->progress.state.info = "disconnected"; - } else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) { - curl->progress.state.info = "redirect"; - } - php_http_client_progress_notify(&curl->progress TSRMLS_CC); - break; - case CURLINFO_HEADER_OUT: - case CURLINFO_DATA_OUT: - case CURLINFO_SSL_DATA_OUT: - curl->progress.state.info = "send"; - break; - case CURLINFO_HEADER_IN: - case CURLINFO_DATA_IN: - case CURLINFO_SSL_DATA_IN: - curl->progress.state.info = "receive"; - break; - default: - break; - } - /* process data */ - switch (type) { - case CURLINFO_HEADER_IN: - case CURLINFO_DATA_IN: - php_http_buffer_append(h->response.buffer, data, length); - - if (curl->options.redirects) { - flags |= PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS; - } - - if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->response.parser, h->response.buffer, flags, &h->response.message)) { - return -1; - } - break; - - case CURLINFO_HEADER_OUT: - case CURLINFO_DATA_OUT: - php_http_buffer_append(h->request.buffer, data, length); - - if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->request.parser, h->request.buffer, flags, &h->request.message)) { - return -1; - } - break; - default: - break; - } - -#if 0 - /* debug */ - _dpf(type, data, length); -#endif - - return 0; -} - -static int php_http_curl_client_dummy_callback(char *data, size_t n, size_t l, void *s) -{ - return n*l; -} - -static STATUS get_info(CURL *ch, HashTable *info) -{ - char *c; - long l; - double d; - struct curl_slist *s, *p; - zval *subarray, array; - INIT_PZVAL_ARRAY(&array, info); - - /* BEGIN::CURLINFO */ - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) { - add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) { - add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) { - add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) { - add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) { - add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) { - add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) { - add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) { - add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) { - add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) { - add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) { - add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) { - add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { - add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) { - add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) { - add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) { - add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) { - add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) { - add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) { - add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) { - add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) { - add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) { - add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) { - add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) { - MAKE_STD_ZVAL(subarray); - array_init(subarray); - for (p = s; p; p = p->next) { - if (p->data) { - add_next_index_string(subarray, p->data, 1); - } - } - add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray); - curl_slist_free_all(s); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_COOKIELIST, &s)) { - MAKE_STD_ZVAL(subarray); - array_init(subarray); - for (p = s; p; p = p->next) { - if (p->data) { - add_next_index_string(subarray, p->data, 1); - } - } - add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray); - curl_slist_free_all(s); - } - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) { - add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1); - } -#if PHP_HTTP_CURL_VERSION(7,19,0) - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) { - add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1); - } -#endif -#if PHP_HTTP_CURL_VERSION(7,19,0) - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) { - add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d); - } -#endif -#if PHP_HTTP_CURL_VERSION(7,19,4) - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) { - add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l); - } -#endif -#if PHP_HTTP_CURL_VERSION(7,21,0) - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) { - add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l); - } -#endif -#if PHP_HTTP_CURL_VERSION(7,21,0) - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) { - add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1); - } -#endif -#if PHP_HTTP_CURL_VERSION(7,21,0) - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) { - add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l); - } -#endif - - /* END::CURLINFO */ - -#if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL) - { - int i; - zval *ci_array; - struct curl_certinfo *ci; - char *colon, *keyname; - - if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) { - MAKE_STD_ZVAL(ci_array); - array_init(ci_array); - - for (i = 0; i < ci->num_of_certs; ++i) { - s = ci->certinfo[i]; - - MAKE_STD_ZVAL(subarray); - array_init(subarray); - for (p = s; p; p = p->next) { - if (p->data) { - if ((colon = strchr(p->data, ':'))) { - keyname = estrndup(p->data, colon - p->data); - add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1); - efree(keyname); - } else { - add_next_index_string(subarray, p->data, 1); - } - } - } - add_next_index_zval(ci_array, subarray); - } - add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array); - } - } -#endif - add_assoc_string_ex(&array, "error", sizeof("error"), php_http_curl_client_get_storage(ch)->errorbuffer, 1); - - return SUCCESS; -} - -/* curl client options */ - -static php_http_options_t php_http_curl_client_options; - -#define PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN 0x0001 -#define PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR 0x0002 -#define PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS 0x0004 - -static STATUS php_http_curl_client_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_BVAL_P(val) ? 2 : 0)) { - return FAILURE; - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - - if (val) { - php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle); - - if (storage->cookiestore) { - pefree(storage->cookiestore, 1); - } - storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1); - if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore) - || CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore) - ) { - return FAILURE; - } - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (val && Z_TYPE_P(val) != IS_NULL) { - if (curl->options.encode_cookies) { - if (SUCCESS == php_http_url_encode_hash_ex(HASH_OF(val), &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0 TSRMLS_CC)) { - php_http_buffer_fix(&curl->options.cookies); - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { - return FAILURE; - } - } else { - return FAILURE; - } - } else { - HashPosition pos; - php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0); - zval **cookie_val; - - FOREACH_KEYVAL(pos, val, cookie_key, cookie_val) { - zval *zv = php_http_ztyp(IS_STRING, *cookie_val); - - php_http_array_hashkey_stringify(&cookie_key); - php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(zv)); - php_http_array_hashkey_stringfree(&cookie_key); - - zval_ptr_dtor(&zv); - } - - php_http_buffer_fix(&curl->options.cookies); - if (curl->options.cookies.used) { - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) { - return FAILURE; - } - } - } - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - - curl->options.encode_cookies = Z_BVAL_P(val); - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (Z_LVAL_P(val)) { - if (Z_LVAL_P(val) > 0) { - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) { - return FAILURE; - } - } else { - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) PHP_HTTP_G->env.request.time + Z_LVAL_P(val))) { - return FAILURE; - } - } - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) { - return FAILURE; - } - } else { - if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0) - || CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0) - ) { - return FAILURE; - } - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_compress(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - - if (Z_BVAL_P(val)) { - curl->options.headers = curl_slist_append(curl->options.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5"); - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_etag(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - php_http_buffer_t header; - zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"')); - - php_http_buffer_init(&header); - php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val)); - php_http_buffer_fix(&header); - curl->options.headers = curl_slist_append(curl->options.headers, header.data); - php_http_buffer_dtor(&header); - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_range(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(h->ts); - - php_http_buffer_reset(&curl->options.ranges); - - if (val && Z_TYPE_P(val) != IS_NULL) { - HashPosition pos; - zval **rr, **rb, **re; - - FOREACH_VAL(pos, val, rr) { - if (Z_TYPE_PP(rr) == IS_ARRAY) { - if (2 == php_http_array_list(Z_ARRVAL_PP(rr) TSRMLS_CC, 2, &rb, &re)) { - 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))) && - ((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)))) { - zval *rbl = php_http_ztyp(IS_LONG, *rb); - zval *rel = php_http_ztyp(IS_LONG, *re); - - if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) { - php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel)); - } - zval_ptr_dtor(&rbl); - zval_ptr_dtor(&rel); - } - - } - } - } - - if (curl->options.ranges.used) { - curl->options.range_request = 1; - /* ditch last comma */ - curl->options.ranges.data[curl->options.ranges.used - 1] = '\0'; - } - } - - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) { - return FAILURE; - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_resume(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - - if (Z_LVAL_P(val) > 0) { - curl->options.range_request = 1; - } - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) { - return FAILURE; - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - - curl->options.retry.delay = Z_DVAL_P(val); - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - - curl->options.retry.count = Z_LVAL_P(val); - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_redirect(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - - if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L) - || CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val)) - ) { - return FAILURE; - } - return SUCCESS; -} - -static STATUS php_http_curl_client_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - long localport = 0, localportrange = 0; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (val && Z_TYPE_P(val) != IS_NULL) { - zval **z_port_start, *zps_copy = NULL, **z_port_end, *zpe_copy = NULL; - - switch (php_http_array_list(Z_ARRVAL_P(val) TSRMLS_CC, 2, &z_port_start, &z_port_end)) { - case 2: - zps_copy = php_http_ztyp(IS_LONG, *z_port_start); - zpe_copy = php_http_ztyp(IS_LONG, *z_port_end); - localportrange = labs(Z_LVAL_P(zps_copy)-Z_LVAL_P(zpe_copy))+1L; - /* no break */ - case 1: - if (!zps_copy) { - zps_copy = php_http_ztyp(IS_LONG, *z_port_start); - } - 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); - zval_ptr_dtor(&zps_copy); - if (zpe_copy) { - zval_ptr_dtor(&zpe_copy); - } - break; - default: - break; - } - } - if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport) - || CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange) - ) { - return FAILURE; - } - return SUCCESS; -} - -#if PHP_HTTP_CURL_VERSION(7,21,3) -static STATUS php_http_curl_client_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (val && Z_TYPE_P(val) != IS_NULL) { - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - HashPosition pos; - zval **data; - - FOREACH_KEYVAL(pos, val, key, data) { - zval *cpy = php_http_ztyp(IS_STRING, *data); - curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy)); - zval_ptr_dtor(&cpy); - } - - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) { - return FAILURE; - } - } else { - if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) { - return FAILURE; - } - } - return SUCCESS; -} -#endif - -static void php_http_curl_client_options_init(php_http_options_t *registry TSRMLS_DC) -{ - php_http_option_t *opt; - - /* proxy */ - if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - } - php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG); - php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG); - if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - } - php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG); - php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL); -#if PHP_HTTP_CURL_VERSION(7,19,4) - php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING); -#endif - - /* dns */ - if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) { - Z_LVAL(opt->defval) = 60; - } - php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG); -#if PHP_HTTP_CURL_VERSION(7,21,3) - if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) { - opt->setter = php_http_curl_client_option_set_resolve; - } -#endif -#if PHP_HTTP_CURL_VERSION(7,24,0) - if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - } -#endif - - /* limits */ - php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG); - php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG); - - /* LSF weirdance - php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG); - php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG); - */ - - /* connection handling */ - /* crashes - if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) { - Z_LVAL(opt->defval) = 5; - } - */ - php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL); - php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL); - - /* outgoing interface */ - php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING); - if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) { - opt->setter = php_http_curl_client_option_set_portrange; - } - - /* another endpoint port */ - php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG); - - /* RFC4007 zone_id */ -#if PHP_HTTP_CURL_VERSION(7,19,0) - php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG); -#endif - - /* auth */ - if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - } - php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG); - - /* redirects */ - if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) { - opt->setter = php_http_curl_client_option_set_redirect; - } - php_http_option_register(registry, ZEND_STRL("unrestrictedauth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL); -#if PHP_HTTP_CURL_VERSION(7,19,1) - php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_BOOL); -#else - php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POST301, IS_BOOL); -#endif - - /* retries */ - if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) { - opt->setter = php_http_curl_client_option_set_retrycount; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) { - opt->setter = php_http_curl_client_option_set_retrydelay; - } - - /* referer */ - if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) { - ZVAL_BOOL(&opt->defval, 1); - } - - /* useragent */ - if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) { - /* don't check strlen, to allow sending no useragent at all */ - ZVAL_STRING(&opt->defval, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")", 0); - } - - /* resume */ - if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) { - opt->setter = php_http_curl_client_option_set_resume; - } - /* ranges */ - if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) { - opt->setter = php_http_curl_client_option_set_range; - } - - /* etag */ - if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->setter = php_http_curl_client_option_set_etag; - } - - /* compression */ - if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) { - opt->setter = php_http_curl_client_option_set_compress; - } - - /* lastmodified */ - if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) { - opt->setter = php_http_curl_client_option_set_lastmodified; - } - - /* cookies */ - if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) { - opt->setter = php_http_curl_client_option_set_encodecookies; - ZVAL_BOOL(&opt->defval, 1); - } - if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) { - opt->setter = php_http_curl_client_option_set_cookies; - } - - /* cookiesession, don't load session cookies from cookiestore */ - php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL); - /* 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_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; - opt->setter = php_http_curl_client_option_set_cookiestore; - } - - /* maxfilesize */ - php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG); - - /* http protocol version */ - php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG); - - /* timeouts */ - if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS; - Z_DVAL(opt->defval) = 3; - } - - /* tcp */ -#if PHP_HTTP_CURL_VERSION(7,25,0) - php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL); - if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) { - Z_LVAL(opt->defval) = 60; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) { - Z_LVAL(opt->defval) = 60; - } -#endif - - /* 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_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; - } - php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING); - php_http_option_register(registry, ZEND_STRL("certpasswd"), CURLOPT_SSLCERTPASSWD, IS_STRING); - - if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; - } - php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING); - php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING); - 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_curl_client_option_set_ssl_verifyhost; - } - 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_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; -#ifdef PHP_HTTP_CURL_CAINFO - 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_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; - } - if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) { - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_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_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_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_CURL_CLIENT_OPTION_CHECK_STRLEN; - opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR; - } -# 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); -#endif - } -} - -static zval *php_http_curl_client_get_option(php_http_option_t *opt, HashTable *options, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - zval *option; - - if ((option = php_http_option_get(opt, options, NULL))) { - option = php_http_ztyp(opt->type, option); - zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL); - } - return option; -} - -static STATUS php_http_curl_client_set_option(php_http_option_t *opt, zval *val, void *userdata) -{ - php_http_client_t *h = userdata; - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - zval tmp; - STATUS rv = SUCCESS; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (!val) { - val = &opt->defval; - } - - switch (opt->type) { - case IS_BOOL: - if (opt->setter) { - rv = opt->setter(opt, val, h); - } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) { - rv = FAILURE; - } - break; - - case IS_LONG: - if (opt->setter) { - rv = opt->setter(opt, val, h); - } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) { - rv = FAILURE; - } - break; - - case IS_STRING: - if (!(opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN) || Z_STRLEN_P(val)) { - if (!(opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR) || !Z_STRVAL_P(val) || SUCCESS == php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) { - if (opt->setter) { - rv = opt->setter(opt, val, h); - } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val))) { - rv = FAILURE; - } - } - } - break; - - case IS_DOUBLE: - if (opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS) { - tmp = *val; - Z_DVAL(tmp) *= 1000; - val = &tmp; - } - if (opt->setter) { - rv = opt->setter(opt, val, h); - } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) { - rv = FAILURE; - } - break; - - case IS_ARRAY: - if (opt->setter) { - rv = opt->setter(opt, val, h); - } else if (Z_TYPE_P(val) != IS_NULL) { - rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), h); - } - break; - - default: - if (opt->setter) { - rv = opt->setter(opt, val, h); - } else { - rv = FAILURE; - } - break; - } - if (rv != SUCCESS) { - php_http_error(HE_NOTICE, PHP_HTTP_E_CLIENT, "Could not set option %s", opt->name.s); - } - return rv; -} - -/* client ops */ - -static STATUS php_http_curl_client_reset(php_http_client_t *h); - -static php_http_client_t *php_http_curl_client_init(php_http_client_t *h, void *handle) -{ - php_http_curl_client_t *ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "could not initialize curl handle"); - return NULL; - } - - ctx = ecalloc(1, sizeof(*ctx)); - ctx->handle = handle; - php_http_buffer_init(&ctx->options.cookies); - php_http_buffer_init(&ctx->options.ranges); - zend_hash_init(&ctx->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0); - h->ctx = ctx; - -#if defined(ZTS) - curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); -#endif - curl_easy_setopt(handle, CURLOPT_HEADER, 0L); - curl_easy_setopt(handle, CURLOPT_FILETIME, 1L); - curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L); - curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curl_client_dummy_callback); - curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curl_client_raw_callback); - curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curl_client_read_callback); - curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curl_client_ioctl_callback); - curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curl_client_progress_callback); - curl_easy_setopt(handle, CURLOPT_DEBUGDATA, h); - curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, h); - - php_http_curl_client_reset(h); - - return h; -} - -static php_http_client_t *php_http_curl_client_copy(php_http_client_t *from, php_http_client_t *to) -{ - php_http_curl_client_t *ctx = from->ctx; - void *copy; - TSRMLS_FETCH_FROM_CTX(from->ts); - - if (!(copy = php_resource_factory_handle_copy(from->rf, ctx->handle TSRMLS_CC))) { - return NULL; - } - - if (to) { - return php_http_curl_client_init(to, copy); - } else { - return php_http_client_init(NULL, from->ops, from->rf, copy TSRMLS_CC); - } -} - -static void php_http_curl_client_dtor(php_http_client_t *h) -{ - php_http_curl_client_t *ctx = h->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - curl_easy_setopt(ctx->handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(ctx->handle, CURLOPT_PROGRESSFUNCTION, NULL); - curl_easy_setopt(ctx->handle, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(ctx->handle, CURLOPT_DEBUGFUNCTION, NULL); - - php_resource_factory_handle_dtor(h->rf, ctx->handle TSRMLS_CC); - - php_http_buffer_dtor(&ctx->options.ranges); - php_http_buffer_dtor(&ctx->options.cookies); - zend_hash_destroy(&ctx->options.cache); - - if (ctx->options.headers) { - curl_slist_free_all(ctx->options.headers); - ctx->options.headers = NULL; - } - php_http_client_progress_dtor(&ctx->progress TSRMLS_CC); - - efree(ctx); - h->ctx = NULL; -} - -static STATUS php_http_curl_client_reset(php_http_client_t *h) -{ - php_http_curl_client_t *curl = h->ctx; - CURL *ch = curl->handle; - php_http_curl_client_storage_t *st; - - if ((st = php_http_curl_client_get_storage(ch))) { - if (st->url) { - pefree(st->url, 1); - st->url = NULL; - } - if (st->cookiestore) { - pefree(st->cookiestore, 1); - st->cookiestore = NULL; - } - st->errorbuffer[0] = '\0'; - } - - curl_easy_setopt(ch, CURLOPT_URL, NULL); - /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */ -#if PHP_HTTP_CURL_VERSION(7,19,1) - curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL); - curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL); - curl_easy_setopt(ch, CURLOPT_USERNAME, NULL); - curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL); -#endif - -#if PHP_HTTP_CURL_VERSION(7,21,3) - if (curl->options.resolve) { - curl_slist_free_all(curl->options.resolve); - curl->options.resolve = NULL; - } -#endif - curl->options.retry.count = 0; - curl->options.retry.delay = 0; - curl->options.redirects = 0; - curl->options.encode_cookies = 1; - - if (curl->options.headers) { - curl_slist_free_all(curl->options.headers); - curl->options.headers = NULL; - } - - php_http_buffer_reset(&curl->options.cookies); - php_http_buffer_reset(&curl->options.ranges); - - return SUCCESS; -} - -PHP_HTTP_API STATUS php_http_curl_client_prepare(php_http_client_t *h, php_http_message_t *msg) -{ - size_t body_size; - php_http_curl_client_t *curl = h->ctx; - php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle); - TSRMLS_FETCH_FROM_CTX(h->ts); - - /* request url */ - if (!PHP_HTTP_INFO(msg).request.url) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot request empty URL"); - return FAILURE; - } - storage->errorbuffer[0] = '\0'; - if (storage->url) { - pefree(storage->url, 1); - } - storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 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_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_METHOD, "Cannot use empty request method"); - return FAILURE; - } - break; - } - } - - /* request headers */ - php_http_message_update_headers(msg); - if (zend_hash_num_elements(&msg->hdrs)) { - php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0); - zval **header_val; - HashPosition pos; - php_http_buffer_t header; - - php_http_buffer_init(&header); - FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) { - if (header_key.type == HASH_KEY_IS_STRING) { - zval *header_cpy = php_http_ztyp(IS_STRING, *header_val); - - php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy)); - php_http_buffer_fix(&header); - curl->options.headers = curl_slist_append(curl->options.headers, header.data); - php_http_buffer_reset(&header); - - zval_ptr_dtor(&header_cpy); - } - } - php_http_buffer_dtor(&header); - curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers); - } - - /* attach request body */ - if ((body_size = php_http_message_body_size(msg->body))) { - /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the - * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.« - * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the - * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method - * does not allow a request body. - */ - php_stream_rewind(php_http_message_body_stream(msg->body)); - curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, msg->body); - 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); - } - - return SUCCESS; -} - -static STATUS php_http_curl_client_exec(php_http_client_t *h, php_http_message_t *msg) -{ - uint tries = 0; - CURLcode result; - php_http_curl_client_t *curl = h->ctx; - php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle); - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (SUCCESS != php_http_curl_client_prepare(h, msg)) { - return FAILURE; - } - -retry: - if (CURLE_OK != (result = curl_easy_perform(curl->handle))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "%s; %s (%s)", curl_easy_strerror(result), storage->errorbuffer, storage->url); - - if (EG(exception)) { - add_property_long(EG(exception), "curlCode", result); - } - - if (curl->options.retry.count > tries++) { - switch (result) { - case CURLE_COULDNT_RESOLVE_PROXY: - case CURLE_COULDNT_RESOLVE_HOST: - case CURLE_COULDNT_CONNECT: - case CURLE_WRITE_ERROR: - case CURLE_READ_ERROR: - case CURLE_OPERATION_TIMEDOUT: - case CURLE_SSL_CONNECT_ERROR: - case CURLE_GOT_NOTHING: - case CURLE_SSL_ENGINE_SETFAILED: - case CURLE_SEND_ERROR: - case CURLE_RECV_ERROR: - case CURLE_SSL_ENGINE_INITFAILED: - case CURLE_LOGIN_DENIED: - if (curl->options.retry.delay >= PHP_HTTP_DIFFSEC) { - php_http_sleep(curl->options.retry.delay); - } - goto retry; - default: - break; - } - } else { - return FAILURE; - } - } - - return SUCCESS; -} - -static STATUS php_http_curl_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg) -{ - php_http_curl_client_t *curl = h->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - switch (opt) { - case PHP_HTTP_CLIENT_OPT_SETTINGS: - return php_http_options_apply(&php_http_curl_client_options, arg, h); - break; - - case PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK: - if (curl->progress.in_cb) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot change progress callback while executing it"); - return FAILURE; - } - if (curl->progress.callback) { - php_http_client_progress_dtor(&curl->progress TSRMLS_CC); - } - curl->progress.callback = arg; - break; - - case PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE: - /* are cookies already enabled anyway? */ - if (!php_http_curl_client_get_storage(curl->handle)->cookiestore) { - if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIEFILE, "")) { - return FAILURE; - } - } - break; - - case PHP_HTTP_CLIENT_OPT_COOKIES_RESET: - if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "ALL")) { - return FAILURE; - } - break; - - case PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION: - if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "SESS")) { - return FAILURE; - } - break; - - case PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH: - if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "FLUSH")) { - return FAILURE; - } - break; - - default: - return FAILURE; - } - - return SUCCESS; -} - -static STATUS php_http_curl_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg) -{ - php_http_curl_client_t *curl = h->ctx; - - switch (opt) { - case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO: - *((php_http_client_progress_t **) arg) = &curl->progress; - break; - - case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO: - get_info(curl->handle, arg); - break; - - default: - return FAILURE; - } - - return SUCCESS; -} - -static php_resource_factory_ops_t php_http_curl_client_resource_factory_ops = { - php_http_curl_ctor, - php_http_curl_copy, - php_http_curl_dtor -}; - -static php_http_client_ops_t php_http_curl_client_ops = { - &php_http_curl_client_resource_factory_ops, - php_http_curl_client_init, - php_http_curl_client_copy, - php_http_curl_client_dtor, - php_http_curl_client_reset, - php_http_curl_client_exec, - php_http_curl_client_setopt, - php_http_curl_client_getopt, - (php_http_new_t) php_http_curl_client_object_new_ex, - php_http_curl_client_get_class_entry -}; - -PHP_HTTP_API php_http_client_ops_t *php_http_curl_client_get_ops(void) -{ - return &php_http_curl_client_ops; -} - - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientCURL, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientCURL, method, 0) -#define PHP_HTTP_CURL_CLIENT_ME(method, visibility) PHP_ME(HttpClientCURL, method, PHP_HTTP_ARGS(HttpClientCURL, method), visibility) -#define PHP_HTTP_CURL_CLIENT_CLIENT_MALIAS(me, vis) ZEND_FENTRY(me, ZEND_MN(HttpClient_##me), PHP_HTTP_ARGS(HttpClientCURL, me), vis) - -PHP_HTTP_BEGIN_ARGS(send, 0) - PHP_HTTP_ARG_VAL(request, 0) -PHP_HTTP_END_ARGS; - -static zend_class_entry *php_http_curl_client_class_entry; - -zend_class_entry *php_http_curl_client_get_class_entry(void) -{ - return php_http_curl_client_class_entry; -} - -static zend_function_entry php_http_curl_client_method_entry[] = { - PHP_HTTP_CURL_CLIENT_CLIENT_MALIAS(send, ZEND_ACC_PUBLIC) - EMPTY_FUNCTION_ENTRY -}; - -zend_object_value php_http_curl_client_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return php_http_curl_client_object_new_ex(ce, NULL, NULL TSRMLS_CC); -} - -zend_object_value php_http_curl_client_object_new_ex(zend_class_entry *ce, php_http_client_t *r, php_http_client_object_t **ptr TSRMLS_DC) -{ - zend_object_value ov; - php_http_client_object_t *o; - - o = ecalloc(1, sizeof(php_http_client_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (!(o->client = r)) { - o->client = php_http_client_init(NULL, &php_http_curl_client_ops, NULL, NULL TSRMLS_CC); - } - - if (ptr) { - *ptr = o; - } - - ov.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC); - ov.handlers = php_http_client_get_object_handlers(); - - return ov; -} - - -PHP_MINIT_FUNCTION(http_curl_client) -{ - php_http_options_t *options; - - if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http_client.curl"), &php_http_curl_client_resource_factory_ops, NULL, NULL TSRMLS_CC)) { - return FAILURE; - } - - if ((options = php_http_options_init(&php_http_curl_client_options, 1))) { - options->getter = php_http_curl_client_get_option; - options->setter = php_http_curl_client_set_option; - - php_http_curl_client_options_init(options TSRMLS_CC); - } - - PHP_HTTP_REGISTER_CLASS(http\\Curl, Client, http_curl_client, php_http_client_get_class_entry(), 0); - php_http_curl_client_class_entry->create_object = php_http_curl_client_object_new; - - /* - * HTTP Protocol Version Constants - */ - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_1_0"), CURL_HTTP_VERSION_1_0 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_1_1"), CURL_HTTP_VERSION_1_1 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_NONE"), CURL_HTTP_VERSION_NONE TSRMLS_CC); /* to be removed */ - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_ANY"), CURL_HTTP_VERSION_NONE TSRMLS_CC); - - /* - * SSL Version Constants - */ - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_TLSv1"), CURL_SSLVERSION_TLSv1 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_SSLv2"), CURL_SSLVERSION_SSLv2 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_SSLv3"), CURL_SSLVERSION_SSLv3 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_ANY"), CURL_SSLVERSION_DEFAULT TSRMLS_CC); - - /* - * DNS IPvX resolving - */ - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_V4"), CURL_IPRESOLVE_V4 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_V6"), CURL_IPRESOLVE_V6 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_ANY"), CURL_IPRESOLVE_WHATEVER TSRMLS_CC); - - /* - * Auth Constants - */ - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_BASIC"), CURLAUTH_BASIC TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_DIGEST"), CURLAUTH_DIGEST TSRMLS_CC); -#if PHP_HTTP_CURL_VERSION(7,19,3) - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_DIGEST_IE"), CURLAUTH_DIGEST_IE TSRMLS_CC); -#endif - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_NTLM"), CURLAUTH_NTLM TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_GSSNEG"), CURLAUTH_GSSNEGOTIATE TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_ANY"), CURLAUTH_ANY TSRMLS_CC); - - /* - * Proxy Type Constants - */ - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS4"), CURLPROXY_SOCKS4 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS4A"), CURLPROXY_SOCKS5 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS5_HOSTNAME"), CURLPROXY_SOCKS5 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS5"), CURLPROXY_SOCKS5 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_HTTP"), CURLPROXY_HTTP TSRMLS_CC); -# if PHP_HTTP_CURL_VERSION(7,19,4) - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_HTTP_1_0"), CURLPROXY_HTTP_1_0 TSRMLS_CC); -# endif - - /* - * Post Redirection Constants - */ -#if PHP_HTTP_CURL_VERSION(7,19,1) - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_301"), CURL_REDIR_POST_301 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_302"), CURL_REDIR_POST_302 TSRMLS_CC); - zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_ALL"), CURL_REDIR_POST_ALL TSRMLS_CC); -#endif - - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(http_curl_client) -{ - php_http_options_dtor(&php_http_curl_client_options); - return SUCCESS; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/php_http_curl_client.h b/php_http_curl_client.h deleted file mode 100644 index ae2a0b8..0000000 --- a/php_http_curl_client.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_CURL_CLIENT_H -#define PHP_HTTP_CURL_CLIENT_H - -#if PHP_HTTP_HAVE_CURL - -PHP_HTTP_API php_http_client_ops_t *php_http_curl_client_get_ops(void); - -typedef struct php_http_curl_client { - CURL *handle; - - struct { - HashTable cache; - - struct curl_slist *headers; - struct curl_slist *resolve; - php_http_buffer_t cookies; - php_http_buffer_t ranges; - - long redirects; - unsigned range_request:1; - unsigned encode_cookies:1; - - struct { - uint count; - double delay; - } retry; - - } options; - - php_http_client_progress_t progress; - -} php_http_curl_client_t; - -typedef struct php_http_curl_client_storage { - char *url; - char *cookiestore; - char errorbuffer[0x100]; -} php_http_curl_client_storage_t; - -static inline php_http_curl_client_storage_t *php_http_curl_client_get_storage(CURL *ch) { - php_http_curl_client_storage_t *st = NULL; - - curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st); - - if (!st) { - st = pecalloc(1, sizeof(*st), 1); - curl_easy_setopt(ch, CURLOPT_PRIVATE, st); - curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); - } - - return st; -} - -PHP_HTTP_API STATUS php_http_curl_client_prepare(php_http_client_t *h, php_http_message_t *msg); - -zend_class_entry *php_http_curl_client_get_class_entry(void); - -zend_object_value php_http_curl_client_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_curl_client_object_new_ex(zend_class_entry *ce, php_http_client_t *r, php_http_client_object_t **ptr TSRMLS_DC); - -PHP_MINIT_FUNCTION(http_curl_client); -PHP_MSHUTDOWN_FUNCTION(http_curl_client); - -#endif /* PHP_HTTP_HAVE_CURL */ -#endif /* PHP_HTTP_CURL_CLIENT_H */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/php_http_curl_client_datashare.c b/php_http_curl_client_datashare.c deleted file mode 100644 index 38377cc..0000000 --- a/php_http_curl_client_datashare.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" - -#if PHP_HTTP_HAVE_CURL - -typedef struct php_http_curl_client_datashare { - CURLSH *handle; -} php_http_curl_client_datashare_t; - - -static void *php_http_curlsh_ctor(void *opaque, void *init_arg TSRMLS_DC) -{ - return curl_share_init(); -} - -static void php_http_curlsh_dtor(void *opaque, void *handle TSRMLS_DC) -{ - curl_share_cleanup(handle); -} - - -/* datashare handler ops */ - -static php_http_client_datashare_t *php_http_curl_client_datashare_init(php_http_client_datashare_t *h, void *handle) -{ - php_http_curl_client_datashare_t *curl; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "could not initialize curl share handle"); - return NULL; - } - - curl = ecalloc(1, sizeof(*curl)); - curl->handle = handle; - h->ctx = curl; - - return h; -} - -static void php_http_curl_client_datashare_dtor(php_http_client_datashare_t *h) -{ - php_http_curl_client_datashare_t *curl = h->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); - - efree(curl); - h->ctx = NULL; -} - -static STATUS php_http_curl_client_datashare_attach(php_http_client_datashare_t *h, php_http_client_t *r) -{ - CURLcode rc; - php_http_curl_client_datashare_t *curl = h->ctx; - php_http_curl_client_t *recurl = r->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (r->ops != php_http_curl_client_get_ops()) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Cannot attach a non-curl client to this datashare"); - return FAILURE; - } - - if (CURLE_OK != (rc = curl_easy_setopt(recurl->handle, CURLOPT_SHARE, curl->handle))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Could not attach request to the datashare: %s", curl_easy_strerror(rc)); - return FAILURE; - } - return SUCCESS; -} - -static STATUS php_http_curl_client_datashare_detach(php_http_client_datashare_t *h, php_http_client_t *r) -{ - CURLcode rc; - php_http_curl_client_t *recurl = r->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - - - if (r->ops != php_http_curl_client_get_ops()) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Cannot attach a non-curl client to this datashare"); - return FAILURE; - } - - if (CURLE_OK != (rc = curl_easy_setopt(recurl->handle, CURLOPT_SHARE, NULL))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Could not detach request from the datashare: %s", curl_share_strerror(rc)); - return FAILURE; - } - return SUCCESS; -} - -static STATUS php_http_curl_client_datashare_setopt(php_http_client_datashare_t *h, php_http_client_datashare_setopt_opt_t opt, void *arg) -{ - CURLSHcode rc; - php_http_curl_client_datashare_t *curl = h->ctx; - - switch (opt) { - case PHP_HTTP_CLIENT_DATASHARE_OPT_COOKIES: - if (CURLSHE_OK != (rc = curl_share_setopt(curl->handle, *((zend_bool *) arg) ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE))) { - TSRMLS_FETCH_FROM_CTX(h->ts); - - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Could not %s sharing of cookie data: %s", *((zend_bool *) arg) ? "enable" : "disable", curl_share_strerror(rc)); - return FAILURE; - } - break; - - case PHP_HTTP_CLIENT_DATASHARE_OPT_RESOLVER: - if (CURLSHE_OK != (rc = curl_share_setopt(curl->handle, *((zend_bool *) arg) ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, CURL_LOCK_DATA_DNS))) { - TSRMLS_FETCH_FROM_CTX(h->ts); - - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Could not %s sharing of resolver data: %s", *((zend_bool *) arg) ? "enable" : "disable", curl_share_strerror(rc)); - return FAILURE; - } - break; - -#if PHP_HTTP_CURL_VERSION(7,23,0) - case PHP_HTTP_CLIENT_DATASHARE_OPT_SSLSESSIONS: - if (CURLSHE_OK != (rc = curl_share_setopt(curl->handle, *((zend_bool *) arg) ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, CURL_LOCK_DATA_SSL_SESSION))) { - TSRMLS_FETCH_FROM_CTX(h->ts); - - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_DATASHARE, "Could not %s sharing of SSL session data: %s", *((zend_bool *) arg) ? "enable" : "disable", curl_share_strerror(rc)); - return FAILURE; - } - break; -#endif - - default: - return FAILURE; - } - - return SUCCESS; -} - -static php_resource_factory_ops_t php_http_curlsh_resource_factory_ops = { - php_http_curlsh_ctor, - NULL, - php_http_curlsh_dtor -}; - -static php_http_client_datashare_ops_t php_http_curl_client_datashare_ops = { - &php_http_curlsh_resource_factory_ops, - php_http_curl_client_datashare_init, - NULL /* copy */, - php_http_curl_client_datashare_dtor, - NULL /*reset */, - php_http_curl_client_datashare_attach, - php_http_curl_client_datashare_detach, - php_http_curl_client_datashare_setopt, - (php_http_new_t) php_http_curl_client_datashare_object_new_ex, - php_http_curl_client_datashare_get_class_entry -}; - -PHP_HTTP_API php_http_client_datashare_ops_t *php_http_curl_client_datashare_get_ops(void) -{ - return &php_http_curl_client_datashare_ops; -} - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientDataShare, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientDataShare, method, 0) -#define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpClientDataShare, method, PHP_HTTP_ARGS(HttpClientDataShare, method), visibility) - -static zend_class_entry *php_http_curl_client_datashare_class_entry; - -zend_class_entry *php_http_curl_client_datashare_get_class_entry(void) -{ - return php_http_curl_client_datashare_class_entry; -} - -static zend_function_entry php_http_curl_client_datashare_method_entry[] = { - EMPTY_FUNCTION_ENTRY -}; - -zend_object_value php_http_curl_client_datashare_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return php_http_curl_client_datashare_object_new_ex(ce, NULL, NULL TSRMLS_CC); -} - -zend_object_value php_http_curl_client_datashare_object_new_ex(zend_class_entry *ce, php_http_client_datashare_t *share, php_http_client_datashare_object_t **ptr TSRMLS_DC) -{ - zend_object_value ov; - php_http_client_datashare_object_t *o; - - o = ecalloc(1, sizeof(*o)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (share) { - o->share = share; - } else { - o->share = php_http_client_datashare_init(NULL, &php_http_curl_client_datashare_ops, NULL, NULL TSRMLS_CC); - } - - if (ptr) { - *ptr = o; - } - - ov.handle = zend_objects_store_put(o, NULL, php_http_client_datashare_object_free, NULL TSRMLS_CC); - ov.handlers = php_http_client_datashare_get_object_handlers(); - - return ov; -} - - -PHP_MINIT_FUNCTION(http_curl_client_datashare) -{ - if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http_client_datashare.curl"), &php_http_curlsh_resource_factory_ops, NULL, NULL TSRMLS_CC)) { - return FAILURE; - } - - PHP_HTTP_REGISTER_CLASS(http\\Curl\\Client, DataShare, http_curl_client_datashare, php_http_client_datashare_get_class_entry(), 0); - php_http_curl_client_datashare_class_entry->create_object = php_http_curl_client_datashare_object_new; - return SUCCESS; -} - -#endif /* PHP_HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_curl_client_datashare.h b/php_http_curl_client_datashare.h deleted file mode 100644 index 5d2a009..0000000 --- a/php_http_curl_client_datashare.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_CURL_CLIENT_DATASHARE_H -#define PHP_HTTP_CURL_CLIENT_DATASHARE_H - -#if PHP_HTTP_HAVE_CURL - -PHP_HTTP_API php_http_client_datashare_ops_t *php_http_curl_client_datashare_get_ops(void); - -zend_class_entry *php_http_curl_client_datashare_get_class_entry(void); - -zend_object_value php_http_curl_client_datashare_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_curl_client_datashare_object_new_ex(zend_class_entry *ce, php_http_client_datashare_t *share, php_http_client_datashare_object_t **ptr TSRMLS_DC); - -PHP_MINIT_FUNCTION(http_curl_client_datashare); - -#endif /* PHP_HTTP_HAVE_CURL */ - -#endif /* PHP_HTTP_CURL_CLIENT_DATASHARE_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_curl_client_pool.c b/php_http_curl_client_pool.c deleted file mode 100644 index 2fc391e..0000000 --- a/php_http_curl_client_pool.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "php_http_api.h" - -#if PHP_HTTP_HAVE_CURL - -#if PHP_HTTP_HAVE_EVENT -# include -# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) -# 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) -# endif -#endif - -typedef struct php_http_curl_client_pool { - CURLM *handle; - - int unfinished; /* int because of curl_multi_perform() */ - -#if PHP_HTTP_HAVE_EVENT - struct event *timeout; - unsigned useevents:1; - unsigned runsocket:1; -#endif -} php_http_curl_client_pool_t; - -static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC) -{ - return curl_multi_init(); -} - -static void php_http_curlm_dtor(void *opaque, void *handle TSRMLS_DC) -{ - curl_multi_cleanup(handle); -} - - -static void php_http_curl_client_pool_responsehandler(php_http_client_pool_t *pool) -{ - int remaining = 0; - zval **requests; - php_http_curl_client_pool_t *curl = pool->ctx; - TSRMLS_FETCH_FROM_CTX(pool->ts); - - do { - CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining); - - if (msg && CURLMSG_DONE == msg->msg) { - zval **request; - - if (CURLE_OK != msg->data.result) { - php_http_curl_client_storage_t *st = php_http_curl_client_get_storage(msg->easy_handle); - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "%s; %s (%s)", curl_easy_strerror(msg->data.result), STR_PTR(st->errorbuffer), STR_PTR(st->url)); - } - - php_http_client_pool_requests(pool, &requests, NULL); - for (request = requests; *request; ++request) { - php_http_client_object_t *obj = zend_object_store_get_object(*request TSRMLS_CC); - - if (msg->easy_handle == ((php_http_curl_client_t *) (obj->client->ctx))->handle) { - Z_ADDREF_PP(request); - zend_llist_add_element(&pool->clients.finished, request); - php_http_client_object_handle_response(*request TSRMLS_CC); - } - - zval_ptr_dtor(request); - } - efree(requests); - } - } while (remaining); -} - - -#if PHP_HTTP_HAVE_EVENT - -typedef struct php_http_client_pool_event { - struct event evnt; - php_http_client_pool_t *pool; -} php_http_client_pool_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_curl_client_pool_timeout_callback(int socket, short action, void *event_data) -{ - php_http_client_pool_t *pool = event_data; - php_http_curl_client_pool_t *curl = pool->ctx; - -#if DBG_EVENTS - fprintf(stderr, "T"); -#endif - if (curl->useevents) { - CURLMcode rc; - TSRMLS_FETCH_FROM_CTX(pool->ts); - - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished))); - - if (CURLM_OK != rc) { - php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "%s", curl_multi_strerror(rc)); - } - - php_http_curl_client_pool_responsehandler(pool); - } -} - -static void php_http_curl_client_pool_event_callback(int socket, short action, void *event_data) -{ - php_http_client_pool_t *pool = event_data; - php_http_curl_client_pool_t *curl = pool->ctx; - -#if DBG_EVENTS - fprintf(stderr, "E"); -#endif - if (curl->useevents) { - CURLMcode rc = CURLE_OK; - TSRMLS_FETCH_FROM_CTX(pool->ts); - - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished))); - - if (CURLM_OK != rc) { - php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "%s", curl_multi_strerror(rc)); - } - - php_http_curl_client_pool_responsehandler(pool); - - /* 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_curl_client_pool_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data) -{ - php_http_client_pool_t *pool = socket_data; - php_http_curl_client_pool_t *curl = pool->ctx; - -#if DBG_EVENTS - fprintf(stderr, "S"); -#endif - if (curl->useevents) { - int events = EV_PERSIST; - php_http_client_pool_event_t *ev = assign_data; - TSRMLS_FETCH_FROM_CTX(pool->ts); - - if (!ev) { - ev = ecalloc(1, sizeof(php_http_client_pool_event_t)); - ev->pool = pool; - curl_multi_assign(curl->handle, 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_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "Unknown socket action %d", action); - return -1; - } - - event_assign(&ev->evnt, PHP_HTTP_G->curl.event_base, sock, events, php_http_curl_client_pool_event_callback, pool); - event_add(&ev->evnt, NULL); - } - - return 0; -} - -static void php_http_curl_client_pool_timer_callback(CURLM *multi, long timeout_ms, void *timer_data) -{ - php_http_client_pool_t *pool = timer_data; - php_http_curl_client_pool_t *curl = pool->ctx; - -#if DBG_EVENTS - fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms); -#endif - if (curl->useevents) { - - if (timeout_ms < 0) { - php_http_curl_client_pool_timeout_callback(CURL_SOCKET_TIMEOUT, EV_READ|EV_WRITE, pool); - } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) { - struct timeval timeout; - TSRMLS_FETCH_FROM_CTX(pool->ts); - - if (!event_initialized(curl->timeout)) { - event_assign(curl->timeout, PHP_HTTP_G->curl.event_base, CURL_SOCKET_TIMEOUT, 0, php_http_curl_client_pool_timeout_callback, pool); - } else if (event_pending(curl->timeout, EV_TIMEOUT, NULL)) { - event_del(curl->timeout); - } - - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - - event_add(curl->timeout, &timeout); - } - } -} - -#endif /* HAVE_EVENT */ - - -/* pool handler ops */ - -static php_http_client_pool_t *php_http_curl_client_pool_init(php_http_client_pool_t *h, void *handle) -{ - php_http_curl_client_pool_t *curl; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "could not initialize curl pool handle"); - return NULL; - } - - curl = ecalloc(1, sizeof(*curl)); - curl->handle = handle; - curl->unfinished = 0; - h->ctx = curl; - - return h; -} - -static void php_http_curl_client_pool_dtor(php_http_client_pool_t *h) -{ - php_http_curl_client_pool_t *curl = h->ctx; - TSRMLS_FETCH_FROM_CTX(h->ts); - -#if PHP_HTTP_HAVE_EVENT - if (curl->timeout) { - efree(curl->timeout); - curl->timeout = NULL; - } -#endif - curl->unfinished = 0; - php_http_client_pool_reset(h); - - php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); - - efree(curl); - h->ctx = NULL; -} - -static STATUS php_http_curl_client_pool_attach(php_http_client_pool_t *h, php_http_client_t *r, php_http_message_t *m) -{ - php_http_curl_client_pool_t *curl = h->ctx; - php_http_curl_client_t *recurl = r->ctx; - CURLMcode rs; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (r->ops != php_http_curl_client_get_ops()) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Cannot attach a non-curl client to this pool"); - return FAILURE; - } - - if (SUCCESS != php_http_curl_client_prepare(r, m)) { - return FAILURE; - } - - if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, recurl->handle))) { - ++curl->unfinished; - return SUCCESS; - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Could not attach request to pool: %s", curl_multi_strerror(rs)); - return FAILURE; - } -} - -static STATUS php_http_curl_client_pool_detach(php_http_client_pool_t *h, php_http_client_t *r) -{ - php_http_curl_client_pool_t *curl = h->ctx; - php_http_curl_client_t *recurl = r->ctx; - CURLMcode rs; - TSRMLS_FETCH_FROM_CTX(h->ts); - - if (r->ops != php_http_curl_client_get_ops()) { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Cannot attach a non-curl client to this pool"); - return FAILURE; - } - - if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, recurl->handle))) { - return SUCCESS; - } else { - php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT_POOL, "Could not detach request from pool: %s", curl_multi_strerror(rs)); - return FAILURE; - } -} - -#ifdef PHP_WIN32 -# define SELECT_ERROR SOCKET_ERROR -#else -# define SELECT_ERROR -1 -#endif - -static STATUS php_http_curl_client_pool_wait(php_http_client_pool_t *h, struct timeval *custom_timeout) -{ - int MAX; - fd_set R, W, E; - struct timeval timeout; - php_http_curl_client_pool_t *curl = h->ctx; - -#if PHP_HTTP_HAVE_EVENT - if (curl->useevents) { - TSRMLS_FETCH_FROM_CTX(h->ts); - - php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "not implemented"); - return FAILURE; - } -#endif - - if (custom_timeout && timerisset(custom_timeout)) { - timeout = *custom_timeout; - } else { - long max_tout = 1000; - - if ((CURLM_OK == curl_multi_timeout(curl->handle, &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; - } - } - - FD_ZERO(&R); - FD_ZERO(&W); - FD_ZERO(&E); - - if (CURLM_OK == curl_multi_fdset(curl->handle, &R, &W, &E, &MAX)) { - if (MAX == -1) { - php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC)); - return SUCCESS; - } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) { - return SUCCESS; - } - } - return FAILURE; -} - -static int php_http_curl_client_pool_once(php_http_client_pool_t *h) -{ - php_http_curl_client_pool_t *curl = h->ctx; - -#if PHP_HTTP_HAVE_EVENT - if (curl->useevents) { - TSRMLS_FETCH_FROM_CTX(h->ts); - php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "not implemented"); - return FAILURE; - } -#endif - - while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle, &curl->unfinished)); - - php_http_curl_client_pool_responsehandler(h); - - return curl->unfinished; - -} - -static STATUS php_http_curl_client_pool_exec(php_http_client_pool_t *h) -{ - TSRMLS_FETCH_FROM_CTX(h->ts); - -#if PHP_HTTP_HAVE_EVENT - php_http_curl_client_pool_t *curl = h->ctx; - - if (curl->useevents) { - php_http_curl_client_pool_timeout_callback(CURL_SOCKET_TIMEOUT, EV_READ|EV_WRITE, h); - do { - int ev_rc = event_base_dispatch(PHP_HTTP_G->curl.event_base); - -#if DBG_EVENTS - fprintf(stderr, "%c", "X.0"[ev_rc+1]); -#endif - - if (ev_rc < 0) { - php_http_error(HE_ERROR, PHP_HTTP_E_RUNTIME, "Error in event_base_dispatch()"); - return FAILURE; - } - } while (curl->unfinished); - } else -#endif - { - while (php_http_curl_client_pool_once(h)) { - if (SUCCESS != php_http_curl_client_pool_wait(h, NULL)) { -#ifdef PHP_WIN32 - /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */ - php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, "WinSock error: %d", WSAGetLastError()); -#else - php_http_error(HE_WARNING, PHP_HTTP_E_SOCKET, strerror(errno)); -#endif - return FAILURE; - } - } - } - - return SUCCESS; -} - -static STATUS php_http_curl_client_pool_setopt(php_http_client_pool_t *h, php_http_client_pool_setopt_opt_t opt, void *arg) -{ - php_http_curl_client_pool_t *curl = h->ctx; - - switch (opt) { - case PHP_HTTP_CLIENT_POOL_OPT_ENABLE_PIPELINING: - if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) { - return FAILURE; - } - break; - - case PHP_HTTP_CLIENT_POOL_OPT_USE_EVENTS: -#if PHP_HTTP_HAVE_EVENT - if ((curl->useevents = *((zend_bool *) arg))) { - 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_curl_client_pool_socket_callback); - curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h); - curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curl_client_pool_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); - } - break; -#endif - - default: - return FAILURE; - } - return SUCCESS; -} - -static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { - php_http_curlm_ctor, - NULL, - php_http_curlm_dtor -}; - -static php_http_client_pool_ops_t php_http_curl_client_pool_ops = { - &php_http_curlm_resource_factory_ops, - php_http_curl_client_pool_init, - NULL /* copy */, - php_http_curl_client_pool_dtor, - NULL /*reset */, - php_http_curl_client_pool_exec, - php_http_curl_client_pool_wait, - php_http_curl_client_pool_once, - php_http_curl_client_pool_attach, - php_http_curl_client_pool_detach, - php_http_curl_client_pool_setopt, - (php_http_new_t) php_http_curl_client_pool_object_new_ex, - php_http_curl_client_pool_get_class_entry -}; - -PHP_HTTP_API php_http_client_pool_ops_t *php_http_curl_client_pool_get_ops(void) -{ - return &php_http_curl_client_pool_ops; -} - -#define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientCURL, method, 0, req_args) -#define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientCURL, method, 0) -#define PHP_HTTP_CURL_ME(method, visibility) PHP_ME(HttpClientCURL, method, PHP_HTTP_ARGS(HttpClientCURL, method), visibility) -#define PHP_HTTP_CURL_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClientCURL, method)) -#define PHP_HTTP_CURL_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClientCURL_##al), PHP_HTTP_ARGS(HttpClientCURL, al), vis) - -static zend_class_entry *php_http_curl_client_pool_class_entry; - -zend_class_entry *php_http_curl_client_pool_get_class_entry(void) -{ - return php_http_curl_client_pool_class_entry; -} - -static zend_function_entry php_http_curl_client_pool_method_entry[] = { - EMPTY_FUNCTION_ENTRY -}; - -zend_object_value php_http_curl_client_pool_object_new(zend_class_entry *ce TSRMLS_DC) -{ - return php_http_curl_client_pool_object_new_ex(ce, NULL, NULL TSRMLS_CC); -} - -zend_object_value php_http_curl_client_pool_object_new_ex(zend_class_entry *ce, php_http_client_pool_t *p, php_http_client_pool_object_t **ptr TSRMLS_DC) -{ - zend_object_value ov; - php_http_client_pool_object_t *o; - - o = ecalloc(1, sizeof(php_http_client_pool_object_t)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (!(o->pool = p)) { - o->pool = php_http_client_pool_init(NULL, &php_http_curl_client_pool_ops, NULL, NULL TSRMLS_CC); - } - - if (ptr) { - *ptr = o; - } - - ov.handle = zend_objects_store_put(o, NULL, php_http_client_pool_object_free, NULL TSRMLS_CC); - ov.handlers = php_http_client_pool_get_object_handlers(); - - return ov; -} - - -PHP_MINIT_FUNCTION(http_curl_client_pool) -{ - if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http_client_pool.curl"), &php_http_curlm_resource_factory_ops, NULL, NULL TSRMLS_CC)) { - return FAILURE; - } - - PHP_HTTP_REGISTER_CLASS(http\\Curl\\Client, Pool, http_curl_client_pool, php_http_client_pool_get_class_entry(), 0); - php_http_curl_client_pool_class_entry->create_object = php_http_curl_client_pool_object_new; - - return SUCCESS; -} - -#if PHP_HTTP_HAVE_EVENT -PHP_RINIT_FUNCTION(http_curl_client_pool) -{ - if (!PHP_HTTP_G->curl.event_base && !(PHP_HTTP_G->curl.event_base = event_base_new())) { - return FAILURE; - } - return SUCCESS; -} -#endif - -#if PHP_HTTP_HAVE_EVENT -PHP_RSHUTDOWN_FUNCTION(http_curl_client_pool) -{ - if (PHP_HTTP_G->curl.event_base) { - event_base_free(PHP_HTTP_G->curl.event_base); - PHP_HTTP_G->curl.event_base = NULL; - } - return SUCCESS; -} -#endif - -#endif /* PHP_HTTP_HAVE_CURL */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_curl_client_pool.h b/php_http_curl_client_pool.h deleted file mode 100644 index 5d6a19c..0000000 --- a/php_http_curl_client_pool.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | PECL :: http | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2004-2011, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_HTTP_CURL_CLIENT_POOL_H -#define PHP_HTTP_CURL_CLIENT_POOL_H - -#if PHP_HTTP_HAVE_CURL - -PHP_HTTP_API php_http_client_pool_ops_t *php_http_curl_client_pool_get_ops(void); - -zend_class_entry *php_http_curl_client_pool_get_class_entry(void); - -zend_object_value php_http_curl_client_pool_object_new(zend_class_entry *ce TSRMLS_DC); -zend_object_value php_http_curl_client_pool_object_new_ex(zend_class_entry *ce, php_http_client_pool_t *p, php_http_client_pool_object_t **ptr TSRMLS_DC); - -#if PHP_HTTP_HAVE_EVENT -struct php_http_curl_globals { - void *event_base; -}; - -PHP_RINIT_FUNCTION(http_curl_client_pool); -PHP_RSHUTDOWN_FUNCTION(http_curl_client_pool); -#endif - -PHP_MINIT_FUNCTION(http_curl_client_pool); - -#endif /* PHP_HTTP_HAVE_CURL */ -#endif /* PHP_HTTP_CURL_CLIENT_POOL_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ - diff --git a/php_http_message.c b/php_http_message.c index 9aa7d12..39d47ff 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -1021,7 +1021,6 @@ zend_object_value php_http_message_object_new(zend_class_entry *ce TSRMLS_DC) zend_object_value php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg, php_http_message_object_t **ptr TSRMLS_DC) { - zend_object_value ov; php_http_message_object_t *o; o = ecalloc(1, sizeof(php_http_message_object_t)); @@ -1040,10 +1039,10 @@ zend_object_value php_http_message_object_new_ex(zend_class_entry *ce, php_http_ o->body = php_http_message_body_object_new_ex(php_http_message_body_get_class_entry(), php_http_message_body_init(&msg->body, NULL TSRMLS_CC), NULL TSRMLS_CC); } - ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_object_free, NULL TSRMLS_CC); - ov.handlers = &php_http_message_object_handlers; + o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_message_object_free, NULL TSRMLS_CC); + o->zv.handlers = &php_http_message_object_handlers; - return ov; + return o->zv; } zend_object_value php_http_message_object_clone(zval *this_ptr TSRMLS_DC) diff --git a/php_http_message.h b/php_http_message.h index 4ba9619..e45cabf 100644 --- a/php_http_message.h +++ b/php_http_message.h @@ -75,6 +75,7 @@ PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, typedef struct php_http_message_object { zend_object zo; + zend_object_value zv; php_http_message_t *message; zend_object_value parent, body; zval *iterator; diff --git a/phpunit/ClientTest.php b/phpunit/ClientTest.php new file mode 100644 index 0000000..21493f3 --- /dev/null +++ b/phpunit/ClientTest.php @@ -0,0 +1,182 @@ +getProgressInfo($r)) $c->pi .= "-"; + } +} +class ProgressObserver2 implements SplObserver { + function update(SplSubject $c, $r = null) { + if ($c->getProgressInfo($r)) $c->pi .= "."; + } +} +class CallbackObserver implements SplObserver { + public $callback; + function __construct($callback) { + $this->callback = $callback; + } + function update(SplSubject $c, $r = null) { + call_user_func($this->callback, $c, $r); + } +} + +class RequestTest extends PHPUnit_Framework_TestCase +{ + /** + * @var http\Client + */ + protected $r; + + function setUp() { + $this->r = new http\Client; + $this->r->pi = ""; + $this->r->setOptions( + array( + "connecttimeout" => 30, + "timeout" => 300, + ) + ); + $this->r->setOptions( + array( + "timeout" => 600 + ) + ); + $this->assertEquals( + array( + "connecttimeout" => 30, + "timeout" => 600, + ), + $this->r->getOptions() + ); + } + + function testObserver() { + $test = $this; + $this->r->attach($o1 = new ProgressObserver1); + $this->r->attach($o2 = new ProgressObserver2); + $this->r->attach( + $o3 = new CallbackObserver( + function ($c, $r) use ($test) { + $p = (array) $c->getProgressInfo($r); + $test->assertArrayHasKey("started", $p); + $test->assertArrayHasKey("finished", $p); + $test->assertArrayHasKey("dlnow", $p); + $test->assertArrayHasKey("ulnow", $p); + $test->assertArrayHasKey("dltotal", $p); + $test->assertArrayHasKey("ultotal", $p); + $test->assertArrayHasKey("info", $p); + } + ) + ); + $this->r->enqueue(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/"))->send(); + $this->assertRegexp("/(\.-)+/", $this->r->pi); + $this->assertCount(3, $this->r->getObservers()); + $this->r->detach($o1); + $this->assertCount(2, $this->r->getObservers()); + $this->r->detach($o2); + $this->assertCount(1, $this->r->getObservers()); + $this->r->detach($o3); + $this->assertCount(0, $this->r->getObservers()); + } + + function testSsl() { + $this->r->setSslOptions(array("verify_peer" => true)); + $this->r->addSslOptions(array("verify_host" => 2)); + $this->assertEquals( + array( + "verify_peer" => true, + "verify_host" => 2, + ), + $this->r->getSslOptions() + ); + $this->r->enqueue($req = new http\Client\Request("GET", "https://twitter.com/")); + $this->r->send(); + $ti = $this->r->getTransferInfo($req); + $this->assertArrayHasKey("ssl_engines", $ti); + $this->assertGreaterThan(0, count($ti["ssl_engines"])); + } + + function testHistory() { + $body = new http\Message\Body; + $body->append("foobar"); + + $request = new http\Client\Request; + $request->setBody($body); + $request->setRequestMethod("POST"); + $request->setRequestUrl("http://dev.iworks.at/ext-http/.print_request.php"); + + $this->r->recordHistory = true; + $this->r->enqueue($request)->send(); + + $this->assertStringMatchesFormat(<<r->getHistory()->toString(true)) + ); + + + $this->r->requeue($request)->send(); + + $this->assertStringMatchesFormat(<<r->getHistory()->toString(true)) + ); + } +} + diff --git a/phpunit/DataShareTest.php b/phpunit/DataShareTest.php deleted file mode 100644 index 6518ce1..0000000 --- a/phpunit/DataShareTest.php +++ /dev/null @@ -1,75 +0,0 @@ -createDataShare(); - - $this->assertFalse($s->dns, "dns"); - $this->assertFalse($s->cookie, "cookie"); - $this->assertFalse($s->ssl, "ssl"); - - $s->dns = true; - $s->cookie = true; - $s->ssl = true; - - $this->assertTrue($s->dns, "dns"); - $this->assertTrue($s->cookie, "cookie"); - $this->assertTrue($s->ssl, "ssl"); - } - } - - function testAttach() { - foreach (http\Client\Factory::getAvailableDrivers() as $driver) { - $f = new http\Client\Factory(compact("driver")); - $s = $f->createDataShare(); - $s->dns = $s->ssl = $s->cookie = true; - $c = $f->createClient(); - $s->attach($c); - $c->setRequest(new http\Client\Request("GET", "https://twitter.com/")); - $s->attach($c); - $cc = clone $c; - $s->attach($cc); - - $this->assertEquals(3, count($s)); - } - } - - function testCurl() { - $client = new http\Curl\Client(array("connecttimeout" => 10)); - $client->setRequest(new http\Client\Request("GET", "https://twitter.com/")); - $share = new http\Curl\Client\DataShare; - $share->ssl = $share->dns = $share->cookie = true; - $share->attach($client); - $share->attach($client2 = clone $client); - $share->attach($client3 = clone $client); - - $this->assertEquals(3, count($share)); - $client->send(); - $client2->send(); - $client3->send(); - - $share->detach($client); - $share->reset(); - } - - function testCurlIncompatible() { - $client = new UserClient; - $client->setRequest(new http\Client\Request("GET", "https://twitter.com")); - - $share = new http\Curl\Client\DataShare; - $this->setExpectedException("PHPUnit_Framework_Error_Warning"); - $share->attach($client); - $this->setExpectedException("PHPUnit_Framework_Error_Warning"); - $share->detach($client); - } -} - diff --git a/phpunit/MessageTest.php b/phpunit/MessageTest.php index 63bc226..b572f57 100644 --- a/phpunit/MessageTest.php +++ b/phpunit/MessageTest.php @@ -204,7 +204,7 @@ class MessageTest extends PHPUnit_Framework_TestCase function testEmptyUrlWarning() { $m = new http\Message; - $this->setExpectedException("PHPUnit_Framework_Error_Warning"); + $this->setExpectedException("PHPUnit_Framework_Error_Notice"); $m->setRequestUrl("/foo"); $m->setType(http\Message::TYPE_REQUEST); $this->setExpectedException("PHPUnit_Framework_Error_Warning"); @@ -238,7 +238,7 @@ class MessageTest extends PHPUnit_Framework_TestCase $d = new http\Encoding\Stream\Deflate; $s = ""; - $m->toCallback(function ($m, $data) use ($d) { + $m->toCallback(function ($m, $data) use ($d, &$s) { $s.=$d->update($data); }); $s.=$d->finish(); diff --git a/phpunit/PoolTest.php b/phpunit/PoolTest.php deleted file mode 100644 index 33dbf9b..0000000 --- a/phpunit/PoolTest.php +++ /dev/null @@ -1,79 +0,0 @@ -createPool(); - - $this->assertFalse($p->dns, "dns"); - $this->assertFalse($p->cookie, "cookie"); - $this->assertFalse($p->ssl, "ssl"); - - $p->dns = true; - $p->cookie = true; - $p->ssl = true; - - $this->assertTrue($p->dns, "dns"); - $this->assertTrue($p->cookie, "cookie"); - $this->assertTrue($p->ssl, "ssl"); - } - }*/ - - function testAttach() { - foreach (http\Client\Factory::getAvailableDrivers() as $driver) { - $f = new http\Client\Factory(compact("driver")); - - $p = $f->createPool(); - $c = $f->createClient(); - - $c->setRequest(new http\Client\Request("GET", "https://twitter.com/")); - $p->attach($c); - - try { - $p->attach($c); - } catch (http\Exception $e) { - $this->assertEquals("Could not attach request to pool: Invalid easy handle", $e->getMessage()); - } - - $cc = clone $c; - $p->attach($cc); - - $this->assertEquals(2, count($p)); - } - } - - function testCurl() { - $client = new http\Curl\Client; - $client->setRequest(new http\Client\Request("GET", "https://twitter.com/")); - $pool = new http\Curl\Client\Pool; - $pool->attach($client); - $pool->attach($client2 = clone $client); - $pool->attach($client3 = clone $client); - - $this->assertEquals(3, count($pool)); - $pool->send(); - - $pool->detach($client); - $this->assertEquals(2, count($pool)); - - $pool->reset(); - $this->assertEquals(0, count($pool)); - } - - function testCurlEvents() { - $client = new http\Curl\Client; - $pool = new http\Curl\Client\Pool; - - $client->setRequest(new http\Client\Request("GET", "https://twitter.com/")); - - $pool->attach($client); - $pool->attach(clone $client); - $pool->attach(clone $client); - - $pool->enableEvents(); - $pool->send(); - } -} - diff --git a/phpunit/RequestTest.php b/phpunit/RequestTest.php deleted file mode 100644 index 0072714..0000000 --- a/phpunit/RequestTest.php +++ /dev/null @@ -1,236 +0,0 @@ -getProgress()) $r->pi .= "-"; - } -} -class ProgressObserver2 implements SplObserver { - function update(SplSubject $r) { - if ($r->getProgress()) $r->pi .= "."; - } -} -class CallbackObserver implements SplObserver { - public $callback; - function __construct($callback) { - $this->callback = $callback; - } - function update(SplSubject $r) { - call_user_func($this->callback, $r); - } -} - -class RequestTest extends PHPUnit_Framework_TestCase -{ - /** - * @var http\Request - */ - protected $r; - - function setUp() { - $f = new http\Client\Factory; - $this->r = $f->createClient(); - $this->r->setOptions( - array( - "connecttimeout" => 30, - "timeout" => 300, - ) - ); - $this->r->setOptions( - array( - "timeout" => 600 - ) - ); - $this->assertEquals( - array( - "connecttimeout" => 30, - "timeout" => 600, - ), - $this->r->getOptions() - ); - } - - function testClone() { - $c = clone $this->r; - $this->assertNotSame($this->r, $c); - } - - function testObserver() { - $test = $this; - $this->r->attach($o1 = new ProgressObserver1); - $this->r->attach($o2 = new ProgressObserver2); - $this->r->attach( - $o3 = new CallbackObserver( - function ($r) use ($test) { - $p = (array) $r->getProgress(); - $test->assertArrayHasKey("started", $p); - $test->assertArrayHasKey("finished", $p); - $test->assertArrayHasKey("dlnow", $p); - $test->assertArrayHasKey("ulnow", $p); - $test->assertArrayHasKey("dltotal", $p); - $test->assertArrayHasKey("ultotal", $p); - $test->assertArrayHasKey("info", $p); - } - ) - ); - $this->r->setRequest(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/"))->send(null); - $this->assertRegexp("/(\.-)+/", $this->r->pi); - $this->assertCount(3, $this->r->getObservers()); - $this->r->detach($o1); - $this->assertCount(2, $this->r->getObservers()); - $this->r->detach($o2); - $this->assertCount(1, $this->r->getObservers()); - $this->r->detach($o3); - $this->assertCount(0, $this->r->getObservers()); - } - - function testCookies() { - $this->r->setRequest(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/.cookie.php"))->send(null); - $this->assertNotContains("Cookie", (string) $this->r->getRequestMessage()); - $this->r->send(null); - $this->assertNotContains("Cookie", (string) $this->r->getRequestMessage()); - $this->r->enableCookies()->send(null); - $this->assertNotContains("Cookie", (string) $this->r->getRequestMessage()); - $this->r->send(null); - $this->assertContains("Cookie", (string) $this->r->getRequestMessage()); - $cookies = $this->r->getResponseMessage()->getCookies(0, array("extra")); - $this->assertCount(2, $cookies); - foreach ($cookies as $cookie) { - if ($cookie->getCookie("perm")) { - $this->assertTrue(0 < $cookie->getExpires()); - } - if ($cookie->getCookie("temp")) { - $this->assertEquals(-1, $cookie->getExpires()); - } - } - $this->r->send(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/.cookie1.php")); - $cookies = $this->r->getResponseMessage()->getCookies(0, array("bar")); - $this->assertCount(1, $cookies); - $cookies = $cookies[0]; - $this->assertEquals(array("bar"=>"foo"), $cookies->getExtras()); - $this->assertEquals(array("foo"=>"bar"), $cookies->getCookies()); - $cookies = $this->r->getResponseMessage()->getCookies(0, array("foo")); - $this->assertCount(1, $cookies); - $cookies = $cookies[0]; - $this->assertEquals(array("foo"=>"bar","bar"=>"foo"), $cookies->getCookies()); - $this->assertEquals(array(), $cookies->getExtras()); - } - - function testResetCookies() { - $this->r->setRequest(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/.cookie.php")); - - $this->r->enableCookies(); - $this->r->send(null); - - $f = function ($a) { return $a->getCookies(); }; - $c = array_map($f, $this->r->getResponseMessage()->getCookies()); - - $this->r->send(null); - $this->assertEquals($c, array_map($f, $this->r->getResponseMessage()->getCookies())); - - $this->r->resetCookies(); - $this->r->send(null); - $this->assertNotEquals($c, array_map($f, $this->r->getResponseMessage()->getCookies())); - } - - function testSsl() { - $this->r->setRequest(new http\Client\Request("GET", "https://twitter.com/")); - $this->r->setSslOptions(array("verify_peer" => true)); - $this->r->addSslOptions(array("verify_host" => 2)); - $this->assertEquals( - array( - "verify_peer" => true, - "verify_host" => 2, - ), - $this->r->getSslOptions() - ); - $this->r->send(); - $ti = $this->r->getTransferInfo(); - $this->assertArrayHasKey("ssl_engines", $ti); - $this->assertGreaterThan(0, count($ti["ssl_engines"])); - } - - function testHistory() { - $body = new http\Message\Body; - $body->append("foobar"); - - $request = new http\Client\Request; - $request->setBody($body); - $request->setRequestMethod("POST"); - $request->setRequestUrl("http://dev.iworks.at/ext-http/.print_request.php"); - - $this->r->recordHistory = true; - $this->r->send($request); - - $this->assertStringMatchesFormat(<<r->getHistory()->toString(true)) - ); - - - $this->r->send($request); - - $this->assertStringMatchesFormat(<<r->getHistory()->toString(true)) - ); - } -} - diff --git a/tests/clientpool002.phpt b/tests/clientpool002.phpt deleted file mode 100644 index 731dd2b..0000000 --- a/tests/clientpool002.phpt +++ /dev/null @@ -1,82 +0,0 @@ ---TEST-- -pool iteration ---SKIPIF-- - ---FILE-- -getAttached() as $c) { - if ($c !== $client) { - echo "."; - } -} -echo "\n"; -echo "Finished: "; -foreach ($pool->getFinished() as $c) { - echo "."; -} -echo "\n"; - -echo "USER\n"; - -$client = new UserClient(); -$pool = new UserPool(); - -echo "Iterator: "; -foreach ($pool as $c) { - if ($c !== $client) { - echo "."; - } -} -echo "\n"; -echo "Attached: "; -foreach ($pool->getAttached() as $c) { - if ($c !== $client) { - echo "."; - } -} -echo "\n"; -echo "Finished: "; -foreach ($pool->getFinished() as $c) { - echo "."; -} -echo "\n"; -?> -Done ---EXPECT-- -Test -CURL -Iterator: -Attached: -Finished: -USER -Iterator: -Attached: -Finished: -Done \ No newline at end of file diff --git a/tests/factory.phpt b/tests/factory.phpt deleted file mode 100644 index 6496913..0000000 --- a/tests/factory.phpt +++ /dev/null @@ -1,71 +0,0 @@ ---TEST-- -factory ---SKIPIF-- - ---FILE-- - "curl")); -$r = $f->createClient(); -$p = $f->createPool(); -$s = $f->createDataShare(); - -$r->setRequest(new http\Client\Request("GET", "http://localhost/")); -$x = $f->createPool($r); -$y = $f->createDatashare($r); - -var_dump( - array_map("get_class", array($f,$r,$p,$s,$x,$y)), - $f->getDriver() -); - -foreach (array("Client", "Pool", "DataShare") as $type) { - try { - $f = new http\Client\Factory(array("driver" => "nonexistant")); - var_dump($f->{"create$type"}()); - } catch (Exception $e) { - echo $e->getMessage(), "\n"; - } -} - -echo "Done\n"; -?> ---EXPECTF-- -Test -array(6) { - [0]=> - string(9) "MyFactory" - [1]=> - string(8) "MyClient" - [2]=> - string(6) "MyPool" - [3]=> - string(7) "MyShare" - [4]=> - string(6) "MyPool" - [5]=> - string(7) "MyShare" -} -string(4) "curl" -clients are not supported by this driver -pools are not supported by this driver -datashares are not supported by this driver -Done diff --git a/tests/requestpool001.phpt b/tests/requestpool001.phpt deleted file mode 100644 index ff91a40..0000000 --- a/tests/requestpool001.phpt +++ /dev/null @@ -1,178 +0,0 @@ ---TEST-- -HttpRequestPool chain ---SKIPIF-- - ---FILE-- -factory = $factory; - $this->dir = (is_dir($cache_dir) or @mkdir($cache_dir)) ? $cache_dir : null; - - foreach (array_map('trim', file($urls_file)) as $url) { - $this->all[$url] = $this->dir ? $this->dir .'/'. md5($url) : null; - } - - $this->send(); - } - - public final function send() - { - if (RMAX) { - $now = array_slice($this->all, 0, RMAX); - $this->rem = array_slice($this->all, RMAX); - } else { - $now = $urls; - $this->rem = array(); - } - - foreach ($now as $url => $file) { - $this->attach( - $this->factory->createClient( - array( - 'redirect' => 5, - 'compress' => GZIP, - 'timeout' => TOUT, - 'connecttimeout' => TOUT, - 'lastmodified' => is_file($file)?filemtime($file):0 - ) - )->setRequest(new http\Client\Request("GET", $url)) - ); - } - - while ($this->once()) { - if (!$this->wait()) { - throw new http\Exception; - } - } - } - - protected final function once() - { - try { - $rc = parent::once(); - } catch (http\Exception $x) { - // a request may have thrown an exception, - // but it is still save to continue - echo $x->getMessage(), "\n"; - } - - foreach ($this->getFinished() as $r) { - $this->detach($r); - - $u = $r->getRequest()->getRequestUrl(); - $c = $r->getResponseMessage()->getResponseCode(); - try { - $b = $r->getResponseMessage()->getBody(); - } catch (\Exception $e) { - echo $e->getMessage(), "\n"; - $b = ""; - } - - printf("%d %s %d\n", $c, $u, strlen($b)); - - if ($c == 200 && $this->dir) { - file_put_contents($this->all[$u], $b); - } - - if ($a = each($this->rem)) { - list($url, $file) = $a; - $this->attach( - $this->factory->createClient( - array( - 'redirect' => 5, - 'compress' => GZIP, - 'timeout' => TOUT, - 'connecttimeout' => TOUT, - 'lastmodified' => is_file($file)?filemtime($file):0 - ) - )->setRequest(new http\Client\Request("GET", $url)) - ); - } - } - return $rc; - } -} - -define('GZIP', true); -define('TOUT', 300); -define('RMAX', 10); -chdir(__DIR__); - -$time = microtime(true); -$factory = new http\Client\Factory(array("driver" => "curl", "clientPoolClass" => "Pool")); -$factory->createPool()->run($factory); -printf("Elapsed: %0.3fs\n", microtime(true)-$time); - -echo "Done\n"; -?> ---EXPECTF-- -%aTEST -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -%d %s %d -Elapsed: %fs -Done diff --git a/tests/serialize001.phpt b/tests/serialize001.phpt index b37b230..411e4a3 100644 --- a/tests/serialize001.phpt +++ b/tests/serialize001.phpt @@ -5,16 +5,6 @@ serialization --FILE-- request = new \http\Client\Request("GET", "http://localhost"); - } - function send($request) { - } -} - $ext = new ReflectionExtension("http"); foreach ($ext->getClasses() as $class) { if ($class->isInstantiable()) { @@ -29,12 +19,6 @@ foreach ($ext->getClasses() as $class) { $unserialized->$m(); } } - if ($class->hasMethod("attach") && !$class->implementsInterface("\\SplSubject")) { - #printf("%s#%s\n", $class->getName(), "attach"); - $c = new http\Curl\Client; - $c->setRequest(new http\Client\Request("GET", "http://localhost")); - $unserialized->attach($c); - } } } ?>