#include "php_http_client_request.h"
#include "php_http_client_response.h"
#include "php_http_client_curl.h"
++#include "php_http_client_curl_user.h"
++#include "php_http_client_curl_event.h"
#include "php_http_url.h"
#include "php_http_version.h"
o->client = client;
- if (ptr) {
- *ptr = o;
- }
+ o->zo.handlers = &php_http_client_object_handlers;
- 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 o;
+}
- return o->zv;
+zend_object *php_http_client_object_new(zend_class_entry *ce)
+{
+ return &php_http_client_object_new_ex(ce, NULL)->zo;
}
-zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC)
+static HashTable *php_http_client_object_get_gc(zval *object, zval **table, int *n)
{
- return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC);
+ php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, object);
+ zend_llist_element *el = NULL;
+ HashTable *props = Z_OBJPROP_P(object);
- uint32_t count = zend_hash_num_elements(props) + zend_llist_count(&obj->client->responses) + zend_llist_count(&obj->client->requests);
++ uint32_t count = zend_hash_num_elements(props) + zend_llist_count(&obj->client->responses) + zend_llist_count(&obj->client->requests) + 1;
+ zval *val;
+
+ *n = 0;
+ *table = obj->gc = erealloc(obj->gc, sizeof(zval) * count);
+
++#if PHP_HTTP_HAVE_CURL
++ if (obj->client->ops == php_http_client_curl_get_ops()) {
++ php_http_client_curl_t *curl = obj->client->ctx;
++
++ if (curl->ev_ops == php_http_client_curl_user_ops_get()) {
++ php_http_client_curl_user_context_t *ctx = curl->ev_ctx;
++
++ ZVAL_COPY_VALUE(&obj->gc[(*n)++], &ctx->user);
++ }
++ }
++#endif
++
+ for (el = obj->client->responses.head; el; el = el->next) {
+ php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
+ ZVAL_OBJ(&obj->gc[(*n)++], &response_obj->zo);
+ }
+
+ for (el = obj->client->requests.head; el; el = el->next) {
- php_http_client_enqueue_t *q = *(php_http_client_enqueue_t **) el->data;
++ php_http_client_enqueue_t *q = (php_http_client_enqueue_t *) el->data;
+ php_http_message_object_t *request_obj = q->opaque; /* FIXME */
+ ZVAL_OBJ(&obj->gc[(*n)++], &request_obj->zo);
+ }
+
+ ZEND_HASH_FOREACH_VAL(props, val)
+ {
+ ZVAL_COPY_VALUE(&obj->gc[(*n)++], val);
+ }
+ ZEND_HASH_FOREACH_END();
+
+ return NULL;
}
-static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response TSRMLS_DC)
+static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response)
{
- 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_class_entry, zipped, NULL TSRMLS_CC);
+ zval new_hist, old_hist_tmp, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0, &old_hist_tmp);
+ php_http_message_t *req_copy = php_http_message_copy(request, NULL);
+ php_http_message_t *res_copy = php_http_message_copy(response, NULL);
+ php_http_message_t *zipped = php_http_message_zip(res_copy, req_copy);
+ php_http_message_object_t *obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped);
- MAKE_STD_ZVAL(new_hist);
- ZVAL_OBJVAL(new_hist, ov, 0);
+ ZVAL_OBJ(&new_hist, &obj->zo);
if (Z_TYPE_P(old_hist) == IS_OBJECT) {
- php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC);
+ php_http_message_object_prepend(&new_hist, old_hist, 1);
}
- zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC);
+ zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), &new_hist);
zval_ptr_dtor(&new_hist);
}
}
}
- #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;
-
- /* ignore and use -1,0 on timeout */
- (void) socket;
- (void) action;
-
- while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished)));
-
- if (CURLM_OK != rc) {
- php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc));
- }
-
- php_http_curlm_responsehandler(context);
- }
- }
-
- static void php_http_curlm_event_callback(int socket, short action, void *event_data)
+ void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action)
{
- php_http_client_t *context = event_data;
- php_http_client_curl_t *curl = context->ctx;
-
- #if DBG_EVENTS
- fprintf(stderr, "E");
- #endif
- if (curl->useevents) {
- CURLMcode rc = CURLM_OK;
-
- while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, socket, etoca(action), &curl->unfinished)));
-
- if (CURLM_OK != rc) {
- php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc));
- }
-
- php_http_curlm_responsehandler(context);
-
- /* remove timeout if there are no transfers left */
- if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- event_del(curl->timeout);
- }
- }
- }
-
- static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
- {
- php_http_client_t *context = socket_data;
- php_http_client_curl_t *curl = context->ctx;
+ CURLMcode rc;
+ php_http_client_curl_t *curl = client->ctx;
- TSRMLS_FETCH_FROM_CTX(client->ts);
#if DBG_EVENTS
- fprintf(stderr, "S");
+ fprintf(stderr, "H");
#endif
- if (curl->useevents) {
- int events = EV_PERSIST;
- php_http_curlm_event_t *ev = assign_data;
-
- if (!ev) {
- ev = ecalloc(1, sizeof(php_http_curlm_event_t));
- ev->context = context;
- curl_multi_assign(curl->handle->multi, sock, ev);
- } else {
- event_del(&ev->evnt);
- }
- switch (action) {
- case CURL_POLL_IN:
- events |= EV_READ;
- break;
- case CURL_POLL_OUT:
- events |= EV_WRITE;
- break;
- case CURL_POLL_INOUT:
- events |= EV_READ|EV_WRITE;
- break;
-
- case CURL_POLL_REMOVE:
- efree(ev);
- /* no break */
- case CURL_POLL_NONE:
- return 0;
-
- default:
- php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action);
- return -1;
- }
+ do {
+ rc = curl_multi_socket_action(curl->handle->multi, s, curl_action, &curl->unfinished);
+ } while (CURLM_CALL_MULTI_PERFORM == rc);
- event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context);
- event_add(&ev->evnt, NULL);
+ if (CURLM_OK != rc) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
++ php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc));
}
- return 0;
+ php_http_client_curl_responsehandler(client);
}
- static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
- {
- php_http_client_t *context = timer_data;
- php_http_client_curl_t *curl = context->ctx;
-
- #if DBG_EVENTS
- fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
- #endif
- if (curl->useevents) {
-
- if (timeout_ms < 0) {
- php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context);
- } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- struct timeval timeout;
-
- if (!event_initialized(curl->timeout)) {
- event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context);
- }
-
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
-
- event_add(curl->timeout, &timeout);
- }
- }
- }
-
- #endif /* HAVE_EVENT */
-
/* curl options */
static php_http_options_t php_http_curle_options, php_http_curlm_options;
static ZEND_RESULT_CODE php_http_curlm_option_set_use_eventloop(php_http_option_t *opt, zval *value, void *userdata)
{
php_http_client_t *client = userdata;
- TSRMLS_FETCH_FROM_CTX(client->ts);
+ php_http_client_curl_ops_t *ev_ops = NULL;
- return php_http_curlm_use_eventloop(client, value && Z_TYPE_P(value) == IS_TRUE);
- }
- if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_class_entry TSRMLS_CC)) {
++ if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_get_class_entry())) {
+ ev_ops = php_http_client_curl_user_ops_get();
+ #if PHP_HTTP_HAVE_EVENT
- } else if (value && z_is_true(value)) {
++ } else if (value && zend_is_true(value)) {
+ ev_ops = php_http_client_curl_event_ops_get();
#endif
+ }
+
+ return php_http_curlm_use_eventloop(client, ev_ops, value);
+ }
static ZEND_RESULT_CODE php_http_curlm_option_set_share_cookies(php_http_option_t *opt, zval *value, void *userdata)
{
}
#endif
/* events */
- #if PHP_HTTP_HAVE_EVENT
- if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, _IS_BOOL))) {
+ if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, 0))) {
opt->setter = php_http_curlm_option_set_use_eventloop;
}
- #endif
/* share */
- if ((opt = php_http_option_register(registry, ZEND_STRL("share_cookies"), 0, IS_BOOL))) {
+ if ((opt = php_http_option_register(registry, ZEND_STRL("share_cookies"), 0, _IS_BOOL))) {
opt->setter = php_http_curlm_option_set_share_cookies;
- ZVAL_BOOL(&opt->defval, 1);
+ ZVAL_TRUE(&opt->defval);
}
#if PHP_HTTP_CURL_VERSION(7,23,0)
- if ((opt = php_http_option_register(registry, ZEND_STRL("share_ssl"), 0, IS_BOOL))) {
+ if ((opt = php_http_option_register(registry, ZEND_STRL("share_ssl"), 0, _IS_BOOL))) {
opt->setter = php_http_curlm_option_set_share_ssl;
- ZVAL_BOOL(&opt->defval, 1);
+ ZVAL_TRUE(&opt->defval);
}
#endif
}
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) {
- if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- event_del(curl->timeout);
- }
- efree(curl->timeout);
- curl->timeout = NULL;
- }
- if (curl->evbase) {
- event_base_free(curl->evbase);
- curl->evbase = NULL;
+ if (curl->ev_ops) {
+ curl->ev_ops->dtor(&curl->ev_ctx);
}
- #endif
curl->unfinished = 0;
- php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC);
+ php_resource_factory_handle_dtor(h->rf, curl->handle);
efree(curl);
h->ctx = NULL;
static ZEND_RESULT_CODE php_http_client_curl_exec(php_http_client_t *h)
{
- #if PHP_HTTP_HAVE_EVENT
php_http_client_curl_t *curl = h->ctx;
- TSRMLS_FETCH_FROM_CTX(h->ts);
- if (curl->useevents) {
- php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
- do {
- int ev_rc = event_base_dispatch(curl->evbase);
-
- #if DBG_EVENTS
- fprintf(stderr, "%c", "X.0"[ev_rc+1]);
- #endif
+ if (curl->ev_ops) {
+ return curl->ev_ops->exec(curl->ev_ctx);
+ }
- if (ev_rc < 0) {
- php_error_docref(NULL, E_ERROR, "Error in event_base_dispatch()");
- return FAILURE;
- }
- } while (curl->unfinished && !EG(exception));
- } else
- #endif
- {
- while (php_http_client_curl_once(h) && !EG(exception)) {
- if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
+ while (php_http_client_curl_once(h) && !EG(exception)) {
+ if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
#ifdef PHP_WIN32
- /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
- php_error_docref(NULL, E_WARNING, "WinSock error: %d", WSAGetLastError());
+ /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
++ php_error_docref(NULL, E_WARNING, "WinSock error: %d", WSAGetLastError());
#else
- php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
++ php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
#endif
- return FAILURE;
- }
+ return FAILURE;
}
}
#if PHP_HTTP_HAVE_CURL
+struct php_http_client_curl_globals {
+ php_http_client_driver_t driver;
+};
+
+ typedef struct php_http_client_curl_handle {
+ CURLM *multi;
+ CURLSH *share;
+ } php_http_client_curl_handle_t;
+
+ typedef struct php_http_client_curl_ops {
+ void *(*init)();
+ void (*dtor)(void **ctx_ptr);
+ ZEND_RESULT_CODE (*once)(void *ctx);
+ ZEND_RESULT_CODE (*wait)(void *ctx, struct timeval *custom_timeout);
+ ZEND_RESULT_CODE (*exec)(void *ctx);
+ } php_http_client_curl_ops_t;
+
+ typedef struct php_http_client_curl {
+ php_http_client_curl_handle_t *handle;
+
+ int unfinished; /* int because of curl_multi_perform() */
+
+ void *ev_ctx;
+ php_http_client_curl_ops_t *ev_ops;
+ } php_http_client_curl_t;
+
+ static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout)
+ {
+ if ((CURLM_OK == curl_multi_timeout(curl->handle->multi, &max_tout)) && (max_tout > 0)) {
+ timeout->tv_sec = max_tout / 1000;
+ timeout->tv_usec = (max_tout % 1000) * 1000;
+ } else {
+ timeout->tv_sec = 0;
+ timeout->tv_usec = 1000;
+ }
+ }
+
+ PHP_HTTP_API void php_http_client_curl_responsehandler(php_http_client_t *client);
+ PHP_HTTP_API void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action);
++PHP_HTTP_API php_http_client_ops_t *php_http_client_curl_get_ops(void);
+
PHP_MINIT_FUNCTION(http_client_curl);
PHP_MSHUTDOWN_FUNCTION(http_client_curl);
++
#endif /* PHP_HTTP_HAVE_CURL */
#endif /* PHP_HTTP_CLIENT_CURL_H */
--- /dev/null
-#include "php_http_client.h"
-#include "php_http_client_curl.h"
+ /*
+ +--------------------------------------------------------------------+
+ | 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-2014, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+ */
+
+ #include "php_http_api.h"
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
+
+ #if PHP_HTTP_HAVE_CURL
+ #if PHP_HTTP_HAVE_EVENT
+ # if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
+ # include <event.h>
+ # define event_base_new event_init
+ # define event_assign(e, b, s, a, cb, d) do {\
+ event_set(e, s, a, cb, d); \
+ event_base_set(b, e); \
+ } while(0)
+ # else
+ # if PHP_HTTP_HAVE_EVENT2
+ # include <event2/event.h>
+ # include <event2/event_struct.h>
+ # else
+ # error "libevent presence is unknown"
+ # endif
+ # endif
+ # ifndef DBG_EVENTS
+ # define DBG_EVENTS 0
+ # endif
+
+ typedef struct php_http_client_curl_event_context {
+ php_http_client_t *client;
+ struct event_base *evbase;
+ struct event *timeout;
+ } php_http_client_curl_event_context_t;
+
+ typedef struct php_http_client_curl_event_ev {
+ struct event evnt;
+ php_http_client_curl_event_context_t *context;
+ } php_http_client_curl_event_ev_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_client_curl_event_handler(void *context, curl_socket_t s, int curl_action)
+ {
+ CURLMcode rc;
+ php_http_client_curl_event_context_t *ctx = context;
+ php_http_client_curl_t *curl = ctx->client->ctx;
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
+
+ #if DBG_EVENTS
+ fprintf(stderr, "H");
+ #endif
+
+ do {
+ rc = curl_multi_socket_action(curl->handle->multi, s, curl_action, &curl->unfinished);
+ } while (CURLM_CALL_MULTI_PERFORM == rc);
+
+ if (CURLM_OK != rc) {
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
++ php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc));
+ }
+
+ php_http_client_curl_responsehandler(ctx->client);
+ }
+
+ static void php_http_client_curl_event_timeout_callback(int socket, short action, void *event_data)
+ {
+ #if DBG_EVENTS
+ fprintf(stderr, "T");
+ #endif
+
+ /* ignore and use -1,0 on timeout */
+ (void) socket;
+ (void) action;
+
+ php_http_client_curl_event_handler(event_data, CURL_SOCKET_TIMEOUT, 0);
+ }
+
+ static void php_http_client_curl_event_timer(CURLM *multi, long timeout_ms, void *timer_data)
+ {
+ php_http_client_curl_event_context_t *context = timer_data;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
+ #endif
+
+ if (timeout_ms < 0) {
+ php_http_client_curl_event_handler(context, CURL_SOCKET_TIMEOUT, 0);
+ } else if (timeout_ms > 0 || !event_initialized(context->timeout) || !event_pending(context->timeout, EV_TIMEOUT, NULL)) {
+ struct timeval timeout;
+
+ if (!event_initialized(context->timeout)) {
+ event_assign(context->timeout, context->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_client_curl_event_timeout_callback, context);
+ }
+
+ timeout.tv_sec = timeout_ms / 1000;
+ timeout.tv_usec = (timeout_ms % 1000) * 1000;
+
+ event_add(context->timeout, &timeout);
+ }
+ }
+
+ static void php_http_client_curl_event_callback(int socket, short action, void *event_data)
+ {
+ php_http_client_curl_event_context_t *ctx = event_data;
+ php_http_client_curl_t *curl = ctx->client->ctx;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "E");
+ #endif
+
+ php_http_client_curl_event_handler(event_data, socket, etoca(action));
+
+ /* remove timeout if there are no transfers left */
+ if (!curl->unfinished && event_initialized(ctx->timeout) && event_pending(ctx->timeout, EV_TIMEOUT, NULL)) {
+ event_del(ctx->timeout);
+ }
+ }
+
+ static int php_http_client_curl_event_socket(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
+ {
+ php_http_client_curl_event_context_t *ctx = socket_data;
+ php_http_client_curl_t *curl = ctx->client->ctx;
+ int events = EV_PERSIST;
+ php_http_client_curl_event_ev_t *ev = assign_data;
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
+
+ #if DBG_EVENTS
+ fprintf(stderr, "S");
+ #endif
+
+ if (!ev) {
+ ev = ecalloc(1, sizeof(*ev));
+ ev->context = ctx;
+ curl_multi_assign(curl->handle->multi, sock, ev);
+ } else {
+ event_del(&ev->evnt);
+ }
+
+ switch (action) {
+ case CURL_POLL_IN:
+ events |= EV_READ;
+ break;
+ case CURL_POLL_OUT:
+ events |= EV_WRITE;
+ break;
+ case CURL_POLL_INOUT:
+ events |= EV_READ|EV_WRITE;
+ break;
+
+ case CURL_POLL_REMOVE:
+ efree(ev);
+ /* no break */
+ case CURL_POLL_NONE:
+ return 0;
+
+ default:
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
++ php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action);
+ return -1;
+ }
+
+ event_assign(&ev->evnt, ctx->evbase, sock, events, php_http_client_curl_event_callback, ctx);
+ event_add(&ev->evnt, NULL);
+
+ return 0;
+ }
+
+ static ZEND_RESULT_CODE php_http_client_curl_event_once(void *context)
+ {
+ php_http_client_curl_event_context_t *ctx = context;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "O");
+ #endif
+
+ if (0 > event_base_loop(ctx->evbase, EVLOOP_NONBLOCK)) {
+ return FAILURE;
+ }
+ return SUCCESS;
+ }
+
+ static ZEND_RESULT_CODE php_http_client_curl_event_wait(void *context, struct timeval *custom_timeout)
+ {
+ php_http_client_curl_event_context_t *ctx = context;
+ struct timeval timeout;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "W");
+ #endif
+
+ if (!event_initialized(ctx->timeout)) {
+ if (0 > event_assign(ctx->timeout, ctx->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_client_curl_event_timeout_callback, ctx)) {
+ return FAILURE;
+ }
+ } else if (custom_timeout && timerisset(custom_timeout)) {
+ if (0 > event_add(ctx->timeout, custom_timeout)) {
+ return FAILURE;
+ }
+ } else if (!event_pending(ctx->timeout, EV_TIMEOUT, NULL)) {
+ php_http_client_curl_get_timeout(ctx->client->ctx, 1000, &timeout);
+ if (0 > event_add(ctx->timeout, &timeout)) {
+ return FAILURE;
+ }
+ }
+
+ if (0 > event_base_loop(ctx->evbase, EVLOOP_ONCE)) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+ }
+
+ static ZEND_RESULT_CODE php_http_client_curl_event_exec(void *context)
+ {
+ php_http_client_curl_event_context_t *ctx = context;
+ php_http_client_curl_t *curl = ctx->client->ctx;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "E");
+ #endif
+
+ /* kickstart */
+ php_http_client_curl_event_handler(ctx, CURL_SOCKET_TIMEOUT, 0);
+
+ do {
+ if (0 > event_base_dispatch(ctx->evbase)) {
+ return FAILURE;
+ }
+ } while (curl->unfinished && !EG(exception));
+
+ return SUCCESS;
+ }
+
+ static void *php_http_client_curl_event_init(php_http_client_t *client)
+ {
+ php_http_client_curl_t *curl = client->ctx;
+ php_http_client_curl_event_context_t *ctx;
+ struct event_base *evb = event_base_new();
+
+ #if DBG_EVENTS
+ fprintf(stderr, "I");
+ #endif
+
+ if (!evb) {
+ return NULL;
+ }
+
+ ctx = ecalloc(1, sizeof(*ctx));
+ ctx->client = client;
+ ctx->evbase = evb;
+ ctx->timeout = ecalloc(1, sizeof(struct event));
+
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, ctx);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_client_curl_event_socket);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, ctx);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_client_curl_event_timer);
+
+ return ctx;
+ }
+
+ static void php_http_client_curl_event_dtor(void **context)
+ {
+ php_http_client_curl_event_context_t *ctx = *context;
+ php_http_client_curl_t *curl;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "D");
+ #endif
+
+ curl = ctx->client->ctx;
+
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL);
+
+ if (event_initialized(ctx->timeout) && event_pending(ctx->timeout, EV_TIMEOUT, NULL)) {
+ event_del(ctx->timeout);
+ }
+ efree(ctx->timeout);
+ event_base_free(ctx->evbase);
+
+ efree(ctx);
+ *context = NULL;
+ }
+
+ static php_http_client_curl_ops_t php_http_client_curl_event_ops = {
+ &php_http_client_curl_event_init,
+ &php_http_client_curl_event_dtor,
+ &php_http_client_curl_event_once,
+ &php_http_client_curl_event_wait,
+ &php_http_client_curl_event_exec,
+ };
+
+ php_http_client_curl_ops_t *php_http_client_curl_event_ops_get()
+ {
+ return &php_http_client_curl_event_ops;
+ }
+
+ #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
+ */
--- /dev/null
+ /*
+ +--------------------------------------------------------------------+
+ | 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-2014, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+ */
+
++#ifndef PHP_HTTP_CLIENT_CURL_EVENT_H
++#define PHP_HTTP_CLIENT_CURL_EVENT_H
++
+ #if PHP_HTTP_HAVE_CURL
+ #if PHP_HTTP_HAVE_EVENT
+
+ php_http_client_curl_ops_t *php_http_client_curl_event_ops_get();
+
+ #endif
+ #endif
+
++#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
+ */
--- /dev/null
-#include "php_http_client.h"
-#include "php_http_client_curl.h"
-#include "php_http_client_curl_user.h"
+ /*
+ +--------------------------------------------------------------------+
+ | 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-2014, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+ */
+
+ #include "php_http_api.h"
-typedef struct php_http_client_curl_user_context {
- php_http_client_t *client;
- zval *user;
- zend_function closure;
- php_http_object_method_t timer;
- php_http_object_method_t socket;
- php_http_object_method_t once;
- php_http_object_method_t wait;
- php_http_object_method_t send;
-} php_http_client_curl_user_context_t;
-
+
+ #include "php_network.h"
+ #include "zend_closures.h"
+
+ #if PHP_HTTP_HAVE_CURL
+
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|rl", &zclient, php_http_client_class_entry, &zstream, &action)) {
+ typedef struct php_http_client_curl_user_ev {
+ php_stream *socket;
+ php_http_client_curl_user_context_t *context;
+ } php_http_client_curl_user_ev_t;
+
+ static void php_http_client_curl_user_handler(INTERNAL_FUNCTION_PARAMETERS)
+ {
+ zval *zstream = NULL, *zclient = NULL;
+ php_stream *stream = NULL;
+ long action = 0;
+ php_socket_t fd = CURL_SOCKET_TIMEOUT;
+ php_http_client_object_t *client = NULL;
+
- client = zend_object_store_get_object(zclient TSRMLS_CC);
++ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "O|rl", &zclient, php_http_client_get_class_entry(), &zstream, &action)) {
+ return;
+ }
+
- php_stream_from_zval(stream, &zstream);
++ client = PHP_HTTP_OBJ(NULL, zclient);
+ if (zstream) {
- zval **args[1], *ztimeout;
- TSRMLS_FETCH_FROM_CTX(context->client->ts);
++ php_stream_from_zval(stream, zstream);
+
+ if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void *) &fd, 1)) {
+ return;
+ }
+ }
+ php_http_client_curl_loop(client->client, fd, action);
+ }
+
+ static void php_http_client_curl_user_timer(CURLM *multi, long timeout_ms, void *timer_data)
+ {
+ php_http_client_curl_user_context_t *context = timer_data;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
+ #endif
+
+ if (timeout_ms <= 0) {
+ php_http_client_curl_loop(context->client, CURL_SOCKET_TIMEOUT, 0);
+ } else if (timeout_ms > 0) {
- MAKE_STD_ZVAL(ztimeout);
++ zval args[1], *ztimeout = &args[0];
+
- args[0] = &ztimeout;
- php_http_object_method_call(&context->timer, context->user, NULL, 1, args TSRMLS_CC);
- zval_ptr_dtor(&ztimeout);
+ ZVAL_LONG(ztimeout, timeout_ms);
- zval **args[2], *zaction, *zsocket;
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
++ php_http_object_method_call(&context->timer, &context->user, NULL, 1, args);
++ zval_ptr_dtor(ztimeout);
+ }
+ }
+
+ static int php_http_client_curl_user_socket(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
+ {
+ php_http_client_curl_user_context_t *ctx = socket_data;
+ php_http_client_curl_t *curl = ctx->client->ctx;
+ php_http_client_curl_user_ev_t *ev = assign_data;
- MAKE_STD_ZVAL(zsocket);
++ zval args[2], *zaction = &args[1], *zsocket = &args[0];
+
+ #if DBG_EVENTS
+ fprintf(stderr, "S");
+ #endif
+
+ if (!ev) {
+ ev = ecalloc(1, sizeof(*ev));
+ ev->context = ctx;
+ ev->socket = php_stream_sock_open_from_socket(sock, NULL);
+
+ curl_multi_assign(curl->handle->multi, sock, ev);
+ }
+
+ switch (action) {
+ case CURL_POLL_IN:
+ case CURL_POLL_OUT:
+ case CURL_POLL_INOUT:
+ case CURL_POLL_REMOVE:
+ case CURL_POLL_NONE:
- args[0] = &zsocket;
- MAKE_STD_ZVAL(zaction);
+ php_stream_to_zval(ev->socket, zsocket);
- args[1] = &zaction;
- php_http_object_method_call(&ctx->socket, ctx->user, NULL, 2, args TSRMLS_CC);
- zval_ptr_dtor(&zsocket);
- zval_ptr_dtor(&zaction);
++ Z_TRY_ADDREF_P(zsocket);
+ ZVAL_LONG(zaction, action);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
++ php_http_object_method_call(&ctx->socket, &ctx->user, NULL, 2, args);
++ zval_ptr_dtor(zsocket);
++ zval_ptr_dtor(zaction);
+ break;
+
+ default:
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
++ php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action);
+ return -1;
+ }
+
+ if (action == CURL_POLL_REMOVE && ev) {
++ php_stream_close(ev->socket);
+ efree(ev);
++ curl_multi_assign(curl->handle->multi, sock, NULL);
+ }
+ return 0;
+ }
+
+ static ZEND_RESULT_CODE php_http_client_curl_user_once(void *context)
+ {
+ php_http_client_curl_user_context_t *ctx = context;
- return php_http_object_method_call(&ctx->once, ctx->user, NULL, 0, NULL TSRMLS_CC);
+
+ #if DBG_EVENTS
+ fprintf(stderr, "O");
+ #endif
+
- zval **args[1], *ztimeout;
++ return php_http_object_method_call(&ctx->once, &ctx->user, NULL, 0, NULL);
+ }
+
+ static ZEND_RESULT_CODE php_http_client_curl_user_wait(void *context, struct timeval *custom_timeout)
+ {
+ php_http_client_curl_user_context_t *ctx = context;
+ struct timeval timeout;
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
++ zval args[1], *ztimeout = &args[0];
+ ZEND_RESULT_CODE rv;
- MAKE_STD_ZVAL(ztimeout);
+
+ #if DBG_EVENTS
+ fprintf(stderr, "W");
+ #endif
+
+ if (!custom_timeout || !timerisset(custom_timeout)) {
+ php_http_client_curl_get_timeout(ctx->client->ctx, 1000, &timeout);
+ custom_timeout = &timeout;
+ }
+
- args[0] = &ztimeout;
- rv = php_http_object_method_call(&ctx->wait, ctx->user, NULL, 1, args TSRMLS_CC);
- zval_ptr_dtor(&ztimeout);
+ ZVAL_LONG(ztimeout, custom_timeout->tv_sec * 1000 + custom_timeout->tv_usec / 1000);
- TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
++ rv = php_http_object_method_call(&ctx->wait, &ctx->user, NULL, 1, args);
++ zval_ptr_dtor(ztimeout);
+
+ return rv;
+ }
+
+ static ZEND_RESULT_CODE php_http_client_curl_user_exec(void *context)
+ {
+ php_http_client_curl_user_context_t *ctx = context;
+ php_http_client_curl_t *curl = ctx->client->ctx;
- if (SUCCESS != php_http_object_method_call(&ctx->send, ctx->user, NULL, 0, NULL TSRMLS_CC)) {
+
+ #if DBG_EVENTS
+ fprintf(stderr, "E");
+ #endif
+
+ /* kickstart */
+ php_http_client_curl_loop(ctx->client, CURL_SOCKET_TIMEOUT, 0);
+
+ do {
- zval *zclosure, **args[1];
- TSRMLS_FETCH_FROM_CTX(client->ts);
++ if (SUCCESS != php_http_object_method_call(&ctx->send, &ctx->user, NULL, 0, NULL)) {
+ return FAILURE;
+ }
+ } while (curl->unfinished && !EG(exception));
+
+ return SUCCESS;
+ }
+
+ static void *php_http_client_curl_user_init(php_http_client_t *client, void *user_data)
+ {
+ php_http_client_curl_t *curl = client->ctx;
+ php_http_client_curl_user_context_t *ctx;
+ php_http_object_method_t init;
- ctx->user = user_data;
- Z_ADDREF_P(ctx->user);
++ zval args[1], *zclosure = &args[0];
+
+ #if DBG_EVENTS
+ fprintf(stderr, "I");
+ #endif
+
+ ctx = ecalloc(1, sizeof(*ctx));
+ ctx->client = client;
- ctx->closure.common.function_name = "php_http_client_curl_user_handler";
++ ZVAL_COPY(&ctx->user, user_data);
+
+ memset(&ctx->closure, 0, sizeof(ctx->closure));
+ ctx->closure.common.type = ZEND_INTERNAL_FUNCTION;
- MAKE_STD_ZVAL(zclosure);
- zend_create_closure(zclosure, &ctx->closure, NULL, NULL TSRMLS_CC);
- args[0] = &zclosure;
++ ctx->closure.common.function_name = zend_string_init(ZEND_STRL("php_http_client_curl_user_handler"), 0);
+ ctx->closure.internal_function.handler = php_http_client_curl_user_handler;
+
- php_http_object_method_init(&init, ctx->user, ZEND_STRL("init") TSRMLS_CC);
- php_http_object_method_call(&init, ctx->user, NULL, 1, args TSRMLS_CC);
++ zend_create_closure(zclosure, &ctx->closure, NULL, NULL, NULL);
+
- zval_ptr_dtor(&zclosure);
++ php_http_object_method_init(&init, &ctx->user, ZEND_STRL("init"));
++ php_http_object_method_call(&init, &ctx->user, NULL, 1, args);
+ php_http_object_method_dtor(&init);
- php_http_object_method_init(&ctx->timer, ctx->user, ZEND_STRL("timer") TSRMLS_CC);
- php_http_object_method_init(&ctx->socket, ctx->user, ZEND_STRL("socket") TSRMLS_CC);
- php_http_object_method_init(&ctx->once, ctx->user, ZEND_STRL("once") TSRMLS_CC);
- php_http_object_method_init(&ctx->wait, ctx->user, ZEND_STRL("wait") TSRMLS_CC);
- php_http_object_method_init(&ctx->send, ctx->user, ZEND_STRL("send") TSRMLS_CC);
++ zval_ptr_dtor(zclosure);
+
-zend_class_entry *php_http_client_curl_user_class_entry;
++ php_http_object_method_init(&ctx->timer, &ctx->user, ZEND_STRL("timer"));
++ php_http_object_method_init(&ctx->socket, &ctx->user, ZEND_STRL("socket"));
++ php_http_object_method_init(&ctx->once, &ctx->user, ZEND_STRL("once"));
++ php_http_object_method_init(&ctx->wait, &ctx->user, ZEND_STRL("wait"));
++ php_http_object_method_init(&ctx->send, &ctx->user, ZEND_STRL("send"));
+
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, ctx);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_client_curl_user_socket);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, ctx);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_client_curl_user_timer);
+
+ return ctx;
+ }
+
+ static void php_http_client_curl_user_dtor(void **context)
+ {
+ php_http_client_curl_user_context_t *ctx = *context;
+ php_http_client_curl_t *curl;
+
+ #if DBG_EVENTS
+ fprintf(stderr, "D");
+ #endif
+
+ curl = ctx->client->ctx;
+
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL);
+ curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL);
+
+ php_http_object_method_dtor(&ctx->timer);
+ php_http_object_method_dtor(&ctx->socket);
+ php_http_object_method_dtor(&ctx->once);
+ php_http_object_method_dtor(&ctx->wait);
+ php_http_object_method_dtor(&ctx->send);
+
++ zend_string_release(ctx->closure.common.function_name);
+ zval_ptr_dtor(&ctx->user);
+
+ efree(ctx);
+ *context = NULL;
+ }
+
+ static php_http_client_curl_ops_t php_http_client_curl_user_ops = {
+ &php_http_client_curl_user_init,
+ &php_http_client_curl_user_dtor,
+ &php_http_client_curl_user_once,
+ &php_http_client_curl_user_wait,
+ &php_http_client_curl_user_exec,
+ };
+
+ php_http_client_curl_ops_t *php_http_client_curl_user_ops_get()
+ {
+ return &php_http_client_curl_user_ops;
+ }
+
- ZEND_ARG_TYPE_INFO(0, socket, IS_RESOURCE, 0)
++static zend_class_entry *php_http_client_curl_user_class_entry;
++
++zend_class_entry *php_http_client_curl_user_get_class_entry()
++{
++ return php_http_client_curl_user_class_entry;
++}
+
+ ZEND_BEGIN_ARG_INFO_EX(ai_init, 0, 0, 1)
+ ZEND_ARG_TYPE_INFO(0, run, IS_CALLABLE, 0)
+ ZEND_END_ARG_INFO();
+ ZEND_BEGIN_ARG_INFO_EX(ai_timer, 0, 0, 1)
+ #if PHP_VERSION_ID >= 70000
+ ZEND_ARG_TYPE_INFO(0, timeout_ms, IS_LONG, 0)
+ #else
+ ZEND_ARG_INFO(0, timeout_ms)
+ #endif
+ ZEND_END_ARG_INFO();
+ ZEND_BEGIN_ARG_INFO_EX(ai_socket, 0, 0, 2)
++ ZEND_ARG_INFO(0, socket)
+ #if PHP_VERSION_ID >= 70000
- ZEND_ARG_INFO(0, socket)
+ ZEND_ARG_TYPE_INFO(0, action, IS_LONG, 0)
+ #else
- php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce TSRMLS_CC);
+ ZEND_ARG_INFO(0, action)
+ #endif
+ ZEND_END_ARG_INFO();
+ ZEND_BEGIN_ARG_INFO_EX(ai_once, 0, 0, 0)
+ ZEND_END_ARG_INFO();
+ ZEND_BEGIN_ARG_INFO_EX(ai_wait, 0, 0, 0)
+ #if PHP_VERSION_ID >= 70000
+ ZEND_ARG_TYPE_INFO(0, timeout_ms, IS_LONG, 0)
+ #else
+ ZEND_ARG_INFO(0, timeout_ms)
+ #endif
+ ZEND_END_ARG_INFO();
+ ZEND_BEGIN_ARG_INFO_EX(ai_send, 0, 0, 0)
+ ZEND_END_ARG_INFO();
+
+ static zend_function_entry php_http_client_curl_user_methods[] = {
+ PHP_ABSTRACT_ME(HttpClientCurlUser, init, ai_init)
+ PHP_ABSTRACT_ME(HttpClientCurlUser, timer, ai_timer)
+ PHP_ABSTRACT_ME(HttpClientCurlUser, socket, ai_socket)
+ PHP_ABSTRACT_ME(HttpClientCurlUser, once, ai_once)
+ PHP_ABSTRACT_ME(HttpClientCurlUser, wait, ai_wait)
+ PHP_ABSTRACT_ME(HttpClientCulrUser, send, ai_send)
+ {0}
+ };
+
+ PHP_MINIT_FUNCTION(http_client_curl_user)
+ {
+ zend_class_entry ce = {0};
+
+ INIT_NS_CLASS_ENTRY(ce, "http\\Client\\Curl", "User", php_http_client_curl_user_methods);
- zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE TSRMLS_CC);
- zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_IN"), CURL_POLL_IN TSRMLS_CC);
- zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT TSRMLS_CC);
- zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT TSRMLS_CC);
- zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE TSRMLS_CC);
++ php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce);
+
++ zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE);
++ zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_IN"), CURL_POLL_IN);
++ zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT);
++ zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT);
++ zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE);
+
+ 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
+ */
--- /dev/null
-PHP_HTTP_API zend_class_entry *php_http_client_curl_user_class_entry;
+ /*
+ +--------------------------------------------------------------------+
+ | 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-2014, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+ */
+
++#ifndef PHP_HTTP_CLIENT_CURL_USER_H
++#define PHP_HTTP_CLIENT_CURL_USER_H
++
+ #if PHP_HTTP_HAVE_CURL
+
++typedef struct php_http_client_curl_user_context {
++ php_http_client_t *client;
++ zval user;
++ zend_function closure;
++ php_http_object_method_t timer;
++ php_http_object_method_t socket;
++ php_http_object_method_t once;
++ php_http_object_method_t wait;
++ php_http_object_method_t send;
++} php_http_client_curl_user_context_t;
++
++PHP_HTTP_API zend_class_entry *php_http_client_curl_user_get_class_entry();
+ PHP_HTTP_API php_http_client_curl_ops_t *php_http_client_curl_user_ops_get();
+ PHP_MINIT_FUNCTION(http_client_curl_user);
+
+ #endif
+
+ #if 0
+ <?php
+
+ interface http\Client\Curl\User
+ {
+ const POLL_NONE = 0;
+ const POLL_IN = 1;
+ const POLL_OUT = 2;
+ const POLL_INOUT = 3;
+ const POLL_REMOVE = 4;
+
+ /**
+ * Initialize the loop
+ *
+ * The callback should be run when:
+ * - timeout occurs
+ * - a watched socket needs action
+ *
+ * @param callable $run callback as function(http\Client $client, resource $socket = null, int $action = http\Client\Curl\User::POLL_NONE)
+ */
+ function init(callable $run);
+
+ /**
+ * Register a timeout watcher
+ * @param int $timeout_ms desired timeout with milliseconds resolution
+ */
+ function timer(int $timeout_ms);
+
+ /**
+ * (Un-)Register a socket watcher
+ * @param resource $socket the fd to watch
+ * @param int $poll http\Client\Curl\Loop::POLL_* constant
+ */
+ function socket($socket, int $poll);
+
+ /**
+ * Run the loop as long as it does not block
+ *
+ * Called by http\Client::once()
+ */
+ function once();
+
+ /**
+ * Wait/poll/select (block the loop) until events fire
+ *
+ * Called by http\Client::wait()
+ *
+ * @param int $timeout_ms block for maximal $timeout_ms milliseconds
+ */
+ function wait(int $timeout_ms = null);
+
+ /**
+ * Run the loop
+ *
+ * Called by http\Client::send() while there are unfinished requests and
+ * no exception has occurred
+ */
+ function send();
+ }
+ #endif
+
++#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
+ */
body->refcount = 1;
if (stream) {
- php_stream_auto_cleanup(stream);
- body->stream_id = php_stream_get_resource_id(stream);
- zend_list_addref(body->stream_id);
+ body->res = stream->res;
- ++GC_REFCOUNT(body->res);
} else {
- stream = php_stream_temp_create(TEMP_STREAM_DEFAULT, 0xffff);
- php_stream_auto_cleanup(stream);
- body->stream_id = php_stream_get_resource_id(stream);
+ body->res = php_stream_temp_create(TEMP_STREAM_DEFAULT, 0xffff)->res;
}
- TSRMLS_SET_CTX(body->ts);
++ ++GC_REFCOUNT(body->res);
if (body_ptr) {
*body_ptr = body;
#include "php_http_api.h"
-static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC)
+ #ifndef PHP_HTTP_DEBUG_NEG
+ # define PHP_HTTP_DEBUG_NEG 0
+ #endif
+
+static int php_http_negotiate_sort(const void *first, const void *second)
{
- zval result, *first, *second;
+ Bucket *b1 = (Bucket *) first, *b2 = (Bucket *) second;
+ int result = numeric_compare_function(&b1->val, &b2->val);
- first = *((zval **) (*((Bucket **) a))->pData);
- second= *((zval **) (*((Bucket **) b))->pData);
-
- if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
- return 0;
- }
- return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
+ return (result > 0 ? -1 : (result < 0 ? 1 : 0));
}
#define M_PRI 5
#endif
return match;
}
-
-static int php_http_negotiate_reduce(void *p TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
+static int php_http_negotiate_reduce(zval *p, int num_args, va_list args, zend_hash_key *hash_key)
{
unsigned best_match = 0;
- HashPosition pos;
- php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
- zval **val, *supported = php_http_ztyp(IS_STRING, *(zval **)p);
+ double q = 0;
- zval *value, *q = NULL;
+ php_http_arrkey_t key;
++ zval *value;
+ zend_string *supported = zval_get_string(p);
HashTable *params = va_arg(args, HashTable *);
HashTable *result = va_arg(args, HashTable *);
const char *sep_str = va_arg(args, const char *);
size_t sep_len = va_arg(args, size_t);
- FOREACH_HASH_KEYVAL(pos, params, key, val) {
- if (key.type == HASH_KEY_IS_STRING) {
- unsigned match = php_http_negotiate_match(key.str, key.len-1, Z_STRVAL_P(supported), Z_STRLEN_P(supported), sep_str, sep_len);
+ ZEND_HASH_FOREACH_KEY_VAL(params, key.h, key.key, value)
+ {
+ unsigned match;
+
+ #if PHP_HTTP_DEBUG_NEG
+ fprintf(stderr, "match(%u) > best_match(%u) = %u (q=%f)\n", match, best_match, match>best_match, Z_DVAL_PP(val));
+ #endif
- if (match > best_match) {
- best_match = match;
- q = Z_DVAL_PP(val) - 0.1 / match;
- }
+ php_http_arrkey_stringify(&key, NULL);
+ match = php_http_negotiate_match(key.key->val, key.key->len, supported->val, supported->len, sep_str, sep_len);
+
+ if (match > best_match) {
+ best_match = match;
- q = value;
++ q = Z_DVAL_P(value) - 0.1 / match;
}
+ php_http_arrkey_dtor(&key);
}
+ ZEND_HASH_FOREACH_END();
- if (q && Z_DVAL_P(q) > 0) {
- Z_TRY_ADDREF_P(q);
- zend_hash_update(result, supported, q);
+ if (q > 0) {
- zval *tmp;
++ zval tmp;
+
- MAKE_STD_ZVAL(tmp);
- ZVAL_DOUBLE(tmp, q);
- zend_hash_update(result, Z_STRVAL_P(supported), Z_STRLEN_P(supported) + 1, (void *) &tmp, sizeof(zval *), NULL);
++ ZVAL_DOUBLE(&tmp, q);
++ zend_hash_update(result, supported, &tmp);
}
- zval_ptr_dtor(&supported);
+ zend_string_release(supported);
return ZEND_HASH_APPLY_KEEP;
}
php_http_params_opts_default_get(&opts);
opts.input.str = estrndup(value_str, value_len);
opts.input.len = value_len;
- php_http_params_parse(¶ms, &opts TSRMLS_CC);
+ opts.flags &= ~PHP_HTTP_PARAMS_RFC5987;
+ php_http_params_parse(¶ms, &opts);
efree(opts.input.str);
- INIT_PZVAL(&arr);
array_init(&arr);
- FOREACH_HASH_KEYVAL(pos, ¶ms, key, val) {
+ ZEND_HASH_FOREACH_KEY_VAL(¶ms, key.h, key.key, val)
+ {
double q;
- if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("arguments"), (void *) &arg)
- && IS_ARRAY == Z_TYPE_PP(arg)
- && SUCCESS == zend_hash_find(Z_ARRVAL_PP(arg), ZEND_STRS("q"), (void *) &zq)) {
- zval *tmp = php_http_ztyp(IS_DOUBLE, *zq);
-
- q = Z_DVAL_P(tmp);
- zval_ptr_dtor(&tmp);
+ if ((arg = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("arguments")))
+ && (IS_ARRAY == Z_TYPE_P(arg))
+ && (zq = zend_hash_str_find(Z_ARRVAL_P(arg), ZEND_STRL("q")))) {
+ q = zval_get_double(zq);
} else {
- q = 1.0 - ++i / 100.0;
+ q = 1.0 - (((double) ++i) / 100.0);
}
- if (key.type == HASH_KEY_IS_STRING) {
- add_assoc_double_ex(&arr, key.str, key.len, q);
+#if 0
+ fprintf(stderr, "Q: %s=%1.3f\n", key.key->val, q);
+#endif
+
+ if (key.key) {
+ add_assoc_double_ex(&arr, key.key->val, key.key->len, q);
} else {
- add_index_double(&arr, key.num, q);
+ add_index_double(&arr, key.h, q);
}
- PTR_FREE(key.str);
}
+ ZEND_HASH_FOREACH_END();
- #if 0
+ #if PHP_HTTP_DEBUG_NEG
- zend_print_zval_r(&arr, 1 TSRMLS_CC);
+ zend_print_zval_r(&arr, 1);
#endif
ALLOC_HASHTABLE(result);
{
if (state->val.str) {
if (0 < (state->val.len = state->input.str - state->val.str)) {
- sanitize_value(opts->flags, state->val.str, state->val.len, *(state->current.val), state->rfc5987 TSRMLS_CC);
+ sanitize_value(opts->flags, state->val.str, state->val.len, state->current.val, state->rfc5987);
+ } else {
- ZVAL_EMPTY_STRING(*(state->current.val));
++ ZVAL_EMPTY_STRING(state->current.val);
}
state->rfc5987 = 0;
} else if (state->arg.str) {
return ZEND_HASH_APPLY_KEEP;
}
-static int apply_querystring_filter(void *pData TSRMLS_DC)
++static int apply_querystring_filter(zval *val)
+ {
- zval **val = pData;
-
- switch (Z_TYPE_PP(val)) {
++ switch (Z_TYPE_P(val)) {
+ case IS_NULL:
+ return ZEND_HASH_APPLY_REMOVE;
+ case IS_ARRAY:
+ case IS_OBJECT:
- zend_hash_apply(HASH_OF(*val), apply_querystring_filter TSRMLS_CC);
- if (!zend_hash_num_elements(HASH_OF(*val))) {
++ zend_hash_apply(HASH_OF(val), apply_querystring_filter);
++ if (!zend_hash_num_elements(HASH_OF(val))) {
+ return ZEND_HASH_APPLY_REMOVE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ZEND_HASH_APPLY_KEEP;
+ }
+
-ZEND_RESULT_CODE php_http_querystring_parse(HashTable *ht, const char *str, size_t len TSRMLS_DC)
+ZEND_RESULT_CODE php_http_querystring_parse(HashTable *ht, const char *str, size_t len)
{
ZEND_RESULT_CODE rv = FAILURE;
php_http_params_opts_t opts;
zval_ptr_dtor(&arr);
}
- ZVAL_NULL(&opts.defval);
- MAKE_STD_ZVAL(opts.defval);
- ZVAL_TRUE(opts.defval);
++ ZVAL_TRUE(&opts.defval);
- if (php_http_params_parse(ht, &opts TSRMLS_CC)) {
- zend_hash_apply(ht, apply_querystring TSRMLS_CC);
+ if (php_http_params_parse(ht, &opts)) {
+ zend_hash_apply(ht, apply_querystring);
rv = SUCCESS;
}
}
/* modify qarray */
- if (params) {
+ if (!params) {
- zend_hash_apply(Z_ARRVAL_P(qarray), apply_querystring_filter TSRMLS_CC);
++ zend_hash_apply(Z_ARRVAL_P(qarray), apply_querystring_filter);
+ } else {
- HashPosition pos;
- HashTable *ptr;
- php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
- zval **params_entry, **qarray_entry;
- zval zv, *zv_ptr = NULL;
+ HashTable *ht;
+ php_http_arrkey_t key;
+ zval zv, *params_entry, *qarray_entry;
- INIT_PZVAL(&zv);
ZVAL_NULL(&zv);
/* squeeze the hash out of the zval */
/*
* update
*/
- zval equal, *entry = NULL;
+ zval equal, tmp, *entry = &tmp;
+ ZVAL_UNDEF(&tmp);
/* recursive */
- if (Z_TYPE_PP(params_entry) == IS_ARRAY || Z_TYPE_PP(params_entry) == IS_OBJECT) {
- entry = php_http_zsep(1, IS_ARRAY, *qarray_entry);
- php_http_querystring_update(entry, *params_entry, NULL TSRMLS_CC);
- } else if ((FAILURE == is_identical_function(&equal, *qarray_entry, *params_entry TSRMLS_CC)) || !Z_BVAL(equal)) {
- Z_ADDREF_PP(params_entry);
- entry = *params_entry;
+ if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) {
+ ZVAL_DUP(entry, qarray_entry);
+ convert_to_array(entry);
+ php_http_querystring_update(entry, params_entry, NULL);
- } else if ((FAILURE == is_equal_function(&equal, qarray_entry, params_entry)) || Z_TYPE(equal) != IS_TRUE) {
++ } else if ((FAILURE == is_identical_function(&equal, qarray_entry, params_entry)) || Z_TYPE(equal) != IS_TRUE) {
+ Z_TRY_ADDREF_P(params_entry);
+ entry = params_entry;
}
if (entry) {
--- /dev/null
- function timer($timeout_ms) {
+ --TEST--
+ client curl user handler
+ --SKIPIF--
+ <?php
+ include "skipif.inc";
+ skip_client_test();
+ ?>
+ --FILE--
+ <?php
+ echo "Test\n";
+
+ class UserHandler implements http\Client\Curl\User
+ {
+ private $client;
+ private $run;
+ private $fds = [
+ "R" => [],
+ "W" => []
+ ];
+ private $R = [];
+ private $W = [];
+ private $timeout = 1000;
+
+ function __construct(http\Client $client) {
+ $this->client = $client;
+ }
+
+ function init(callable $run) {
+ $this->run = $run;
+ }
+
- function socket($socket, $action) {
++ function timer(int $timeout_ms) {
+ echo "T";
+ $this->timeout = $timeout_ms;
+ }
+
- function wait($timeout_ms = null) {
++ function socket($socket, int $action) {
+ echo "S";
+
+ switch ($action) {
+ case self::POLL_NONE:
+ break;
+ case self::POLL_REMOVE:
+ if (false !== ($r = array_search($socket, $this->fds["R"], true))) {
+ echo "U";
+ unset($this->fds["R"][$r]);
+ }
+
+ if (false !== ($w = array_search($socket, $this->fds["W"], true))) {
+ echo "U";
+ unset($this->fds["W"][$w]);
+ }
+
+ break;
+
+ default:
+ if ($action & self::POLL_IN) {
+ if (!in_array($socket, $this->fds["R"], true)) {
+ $this->fds["R"][] = $socket;
+ }
+ }
+ if ($action & self::POLL_OUT) {
+ if (!in_array($socket, $this->fds["W"], true)) {
+ $this->fds["W"][] = $socket;
+ }
+ }
+ break;
+ }
+ }
+
+ function once() {
+ echo "O";
+
+ foreach ($this->W as $w) {
+ call_user_func($this->run, $this->client, $w, self::POLL_OUT);
+ }
+ foreach ($this->R as $r) {
+ call_user_func($this->run, $this->client, $r, self::POLL_IN);
+ }
+ return count($this->client);
+ }
+
++ function wait(int $timeout_ms = null) {
+ echo "W";
+
+ if ($timeout_ms === null) {
+ $timeout_ms = $this->timeout;
+ }
+ $ts = floor($timeout_ms / 1000);
+ $tu = ($timeout_ms % 1000) * 1000;
+
+ extract($this->fds);
+
+ if (($wfds = count($R) + count($W))) {
+ $nfds = stream_select($R, $W, $E, $ts, $tu);
+ } else {
+ $nfds = 0;
+ }
+ $this->R = (array) $R;
+ $this->W = (array) $W;
+
+ if ($nfds === false) {
+ return false;
+ }
+ if (!$nfds) {
+ if (!$wfds) {
+ echo "S";
+ time_nanosleep($ts, $tu*1000);
+ }
+ call_user_func($this->run, $this->client);
+ }
+
+ return true;
+ }
+
+ function send() {
+ $this->wait();
+ $this->once();
+ }
+ }
+
+
+ include "helper/server.inc";
+
+ server("proxy.inc", function($port) {
+ $client = new http\Client;
+ $client->configure([
+ "use_eventloop" => new UserHandler($client)
+ ]);
+ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"), function($r) {
+ var_dump($r->getResponseCode());
+ });
+ $client->send();
+ });
+
+ ?>
+ ===DONE===
+ --EXPECTREGEX--
+ Test
+ T[WST]*(O[WST]*)+U+int\(200\)
+ ===DONE===
a.b: Array
(
[a.b] => 0.9
- [a.x] => 0.1
- [c.e] => 0.1
- [c.e] => 0.08
+ [a.x] => 0.08
++ [c.e] => 0.08
)
DONE