From: Michael Wallner Date: Mon, 13 Jun 2016 12:54:41 +0000 (+0200) Subject: Merge branch 'v2.6.x' X-Git-Tag: RELEASE_3_1_0_BETA1~10 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=43a9a6f8cb56e25c3770d652ce77045f89f68ca6;hp=--cc Merge branch 'v2.6.x' --- 43a9a6f8cb56e25c3770d652ce77045f89f68ca6 diff --cc src/php_http_api.h index e8c175f,08b6ba8..b264694 --- a/src/php_http_api.h +++ b/src/php_http_api.h @@@ -101,6 -101,6 +101,8 @@@ #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" diff --cc src/php_http_client.c index 4b465c0,160e8bb..5d2aafe --- a/src/php_http_client.c +++ b/src/php_http_client.c @@@ -348,62 -345,35 +348,74 @@@ php_http_client_object_t *php_http_clie 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); } diff --cc src/php_http_client_curl.c index 423e12e,863b342..be17832 --- a/src/php_http_client_curl.c +++ b/src/php_http_client_curl.c @@@ -729,158 -668,27 +693,26 @@@ void php_http_client_curl_responsehandl } } - #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; @@@ -1775,10 -1582,19 +1604,18 @@@ static inline ZEND_RESULT_CODE php_http static ZEND_RESULT_CODE php_http_curlm_option_set_use_eventloop(php_http_option_t *opt, zval *value, void *userdata) { php_http_client_t *client = userdata; + php_http_client_curl_ops_t *ev_ops = NULL; - TSRMLS_FETCH_FROM_CTX(client->ts); - 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) { @@@ -1866,20 -1684,18 +1703,18 @@@ static void php_http_curlm_options_init } #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 } @@@ -2218,23 -2024,14 +2053,13 @@@ static php_http_client_t *php_http_clie 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; @@@ -2447,36 -2220,22 +2247,21 @@@ static int php_http_client_curl_once(ph 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; } } diff --cc src/php_http_client_curl.h index 9128647,beeb8df..abd8f99 --- a/src/php_http_client_curl.h +++ b/src/php_http_client_curl.h @@@ -15,12 -15,44 +15,50 @@@ #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 */ diff --cc src/php_http_client_curl_event.c index 0000000,058c51f..e1ba505 mode 000000,100644..100644 --- a/src/php_http_client_curl_event.c +++ b/src/php_http_client_curl_event.c @@@ -1,0 -1,332 +1,327 @@@ + /* + +--------------------------------------------------------------------+ + | 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 | + +--------------------------------------------------------------------+ + */ + + #include "php_http_api.h" -#include "php_http_client.h" -#include "php_http_client_curl.h" + + #if PHP_HTTP_HAVE_CURL + #if PHP_HTTP_HAVE_EVENT + # if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000) + # include + # 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 + # include + # 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; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); + + #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) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); ++ 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; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); + + #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: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action); ++ 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; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); + + #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 + */ diff --cc src/php_http_client_curl_event.h index 0000000,d3b0928..4739f62 mode 000000,100644..100644 --- a/src/php_http_client_curl_event.h +++ b/src/php_http_client_curl_event.h @@@ -1,0 -1,28 +1,33 @@@ + /* + +--------------------------------------------------------------------+ + | 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 | + +--------------------------------------------------------------------+ + */ + ++#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 + */ diff --cc src/php_http_client_curl_user.c index 0000000,6fdfa36..a30d666 mode 000000,100644..100644 --- a/src/php_http_client_curl_user.c +++ b/src/php_http_client_curl_user.c @@@ -1,0 -1,346 +1,323 @@@ + /* + +--------------------------------------------------------------------+ + | 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 | + +--------------------------------------------------------------------+ + */ + + #include "php_http_api.h" -#include "php_http_client.h" -#include "php_http_client_curl.h" -#include "php_http_client_curl_user.h" + + #include "php_network.h" + #include "zend_closures.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; - + 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; + - if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|rl", &zclient, php_http_client_class_entry, &zstream, &action)) { ++ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "O|rl", &zclient, php_http_client_get_class_entry(), &zstream, &action)) { + return; + } + - client = zend_object_store_get_object(zclient TSRMLS_CC); ++ client = PHP_HTTP_OBJ(NULL, zclient); + if (zstream) { - php_stream_from_zval(stream, &zstream); ++ 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) { - zval **args[1], *ztimeout; - TSRMLS_FETCH_FROM_CTX(context->client->ts); ++ zval args[1], *ztimeout = &args[0]; + - MAKE_STD_ZVAL(ztimeout); + ZVAL_LONG(ztimeout, timeout_ms); - args[0] = &ztimeout; - php_http_object_method_call(&context->timer, context->user, NULL, 1, args TSRMLS_CC); - zval_ptr_dtor(&ztimeout); ++ 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; - zval **args[2], *zaction, *zsocket; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); ++ 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: - MAKE_STD_ZVAL(zsocket); + php_stream_to_zval(ev->socket, zsocket); - args[0] = &zsocket; - MAKE_STD_ZVAL(zaction); ++ Z_TRY_ADDREF_P(zsocket); + ZVAL_LONG(zaction, action); - 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); ++ php_http_object_method_call(&ctx->socket, &ctx->user, NULL, 2, args); ++ zval_ptr_dtor(zsocket); ++ zval_ptr_dtor(zaction); + break; + + default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action); ++ 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; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); + + #if DBG_EVENTS + fprintf(stderr, "O"); + #endif + - return php_http_object_method_call(&ctx->once, ctx->user, NULL, 0, NULL TSRMLS_CC); ++ 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; - zval **args[1], *ztimeout; ++ zval args[1], *ztimeout = &args[0]; + ZEND_RESULT_CODE rv; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); + + #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; + } + - MAKE_STD_ZVAL(ztimeout); + ZVAL_LONG(ztimeout, custom_timeout->tv_sec * 1000 + custom_timeout->tv_usec / 1000); - args[0] = &ztimeout; - rv = php_http_object_method_call(&ctx->wait, ctx->user, NULL, 1, args TSRMLS_CC); - zval_ptr_dtor(&ztimeout); ++ 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; - TSRMLS_FETCH_FROM_CTX(ctx->client->ts); + + #if DBG_EVENTS + fprintf(stderr, "E"); + #endif + + /* kickstart */ + php_http_client_curl_loop(ctx->client, CURL_SOCKET_TIMEOUT, 0); + + do { - if (SUCCESS != php_http_object_method_call(&ctx->send, ctx->user, NULL, 0, NULL TSRMLS_CC)) { ++ 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; - zval *zclosure, **args[1]; - TSRMLS_FETCH_FROM_CTX(client->ts); ++ zval args[1], *zclosure = &args[0]; + + #if DBG_EVENTS + fprintf(stderr, "I"); + #endif + + ctx = ecalloc(1, sizeof(*ctx)); + ctx->client = client; - ctx->user = user_data; - Z_ADDREF_P(ctx->user); ++ ZVAL_COPY(&ctx->user, user_data); + + memset(&ctx->closure, 0, sizeof(ctx->closure)); + ctx->closure.common.type = ZEND_INTERNAL_FUNCTION; - ctx->closure.common.function_name = "php_http_client_curl_user_handler"; ++ 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; + - MAKE_STD_ZVAL(zclosure); - zend_create_closure(zclosure, &ctx->closure, NULL, NULL TSRMLS_CC); - args[0] = &zclosure; ++ zend_create_closure(zclosure, &ctx->closure, NULL, NULL, NULL); + - 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); ++ 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); - zval_ptr_dtor(&zclosure); ++ zval_ptr_dtor(zclosure); + - 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); ++ 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_class_entry *php_http_client_curl_user_class_entry; ++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_TYPE_INFO(0, socket, IS_RESOURCE, 0) + ZEND_ARG_TYPE_INFO(0, action, IS_LONG, 0) + #else - ZEND_ARG_INFO(0, socket) + 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); - php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce 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 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); ++ 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 + */ diff --cc src/php_http_client_curl_user.h index 0000000,8a6778f..35f5d6f mode 000000,100644..100644 --- a/src/php_http_client_curl_user.h +++ b/src/php_http_client_curl_user.h @@@ -1,0 -1,89 +1,105 @@@ + /* + +--------------------------------------------------------------------+ + | 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 | + +--------------------------------------------------------------------+ + */ + ++#ifndef PHP_HTTP_CLIENT_CURL_USER_H ++#define PHP_HTTP_CLIENT_CURL_USER_H ++ + #if PHP_HTTP_HAVE_CURL + -PHP_HTTP_API zend_class_entry *php_http_client_curl_user_class_entry; ++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 + 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; diff --cc src/php_http_negotiate.c index 9fdad26,02b0a64..cd09d37 --- a/src/php_http_negotiate.c +++ b/src/php_http_negotiate.c @@@ -12,12 -12,21 +12,16 @@@ #include "php_http_api.h" + #ifndef PHP_HTTP_DEBUG_NEG + # define PHP_HTTP_DEBUG_NEG 0 + #endif + -static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC) +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 @@@ -62,38 -75,41 +70,44 @@@ static inline unsigned php_http_negotia #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; + double q = 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); + php_http_arrkey_t key; - zval *value, *q = NULL; ++ 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; } @@@ -112,38 -129,38 +126,39 @@@ HashTable *php_http_negotiate(const cha php_http_params_opts_default_get(&opts); opts.input.str = estrndup(value_str, value_len); opts.input.len = value_len; + opts.flags &= ~PHP_HTTP_PARAMS_RFC5987; - php_http_params_parse(¶ms, &opts TSRMLS_CC); + 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); diff --cc src/php_http_params.c index 8db5c35,c722f06..c9feccb --- a/src/php_http_params.c +++ b/src/php_http_params.c @@@ -553,7 -524,9 +555,9 @@@ static void push_param(HashTable *param { 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) { diff --cc src/php_http_querystring.c index ea84d8d,322bd75..d45cd49 --- a/src/php_http_querystring.c +++ b/src/php_http_querystring.c @@@ -171,7 -161,28 +171,26 @@@ static int apply_querystring(zval *val 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; @@@ -200,10 -213,11 +219,10 @@@ 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; } @@@ -224,11 -238,16 +243,13 @@@ ZEND_RESULT_CODE php_http_querystring_u } /* 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 */ @@@ -268,17 -282,15 +289,17 @@@ /* * 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) { diff --cc tests/client028.phpt index 0000000,4678bcc..27ab2b6 mode 000000,100644..100644 --- a/tests/client028.phpt +++ b/tests/client028.phpt @@@ -1,0 -1,141 +1,141 @@@ + --TEST-- + client curl user handler + --SKIPIF-- + + --FILE-- + [], + "W" => [] + ]; + private $R = []; + private $W = []; + private $timeout = 1000; + + function __construct(http\Client $client) { + $this->client = $client; + } + + function init(callable $run) { + $this->run = $run; + } + - function timer($timeout_ms) { ++ function timer(int $timeout_ms) { + echo "T"; + $this->timeout = $timeout_ms; + } + - function socket($socket, $action) { ++ 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($timeout_ms = null) { ++ 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=== diff --cc tests/negotiate001.phpt index 0e553f5,b4757c0..ff1644b --- a/tests/negotiate001.phpt +++ b/tests/negotiate001.phpt @@@ -122,7 -127,7 +127,7 @@@ CUSTO 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