#include "php_http_api.h"
#include "php_http_client.h"
+#include "php_http_client_curl_event.h"
#if PHP_HTTP_HAVE_CURL
-#if PHP_HTTP_HAVE_EVENT
-# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
-# include <event.h>
-# define event_base_new event_init
-# define event_assign(e, b, s, a, cb, d) do {\
- event_set(e, s, a, cb, d); \
- event_base_set(b, e); \
- } while(0)
-# else
-# if PHP_HTTP_HAVE_EVENT2
-# include <event2/event.h>
-# include <event2/event_struct.h>
-# else
-# error "libevent presence is unknown"
-# endif
-# endif
-# ifndef DBG_EVENTS
-# define DBG_EVENTS 0
-# endif
-#endif
-
#ifdef PHP_HTTP_HAVE_OPENSSL
# include <openssl/ssl.h>
#endif
# include <gnutls.h>
#endif
-typedef struct php_http_client_curl_handle {
- CURLM *multi;
- CURLSH *share;
-} php_http_client_curl_handle_t;
-
-typedef struct php_http_client_curl {
- php_http_client_curl_handle_t *handle;
-
- int unfinished; /* int because of curl_multi_perform() */
-
-#if PHP_HTTP_HAVE_EVENT
- struct event_base *evbase;
- struct event *timeout;
- unsigned useevents:1;
-#endif
-} php_http_client_curl_t;
-
typedef struct php_http_client_curl_handler {
CURL *handle;
php_resource_factory_t *rf;
return response;
}
-static void php_http_curlm_responsehandler(php_http_client_t *context)
+void php_http_client_curl_responsehandler(php_http_client_t *context)
{
int err_count = 0, remaining = 0;
php_http_curle_storage_t *st, *err = NULL;
}
}
-#if PHP_HTTP_HAVE_EVENT
-
-typedef struct php_http_curlm_event {
- struct event evnt;
- php_http_client_t *context;
-} php_http_curlm_event_t;
-
-static inline int etoca(short action) {
- switch (action & (EV_READ|EV_WRITE)) {
- case EV_READ:
- return CURL_CSELECT_IN;
- break;
- case EV_WRITE:
- return CURL_CSELECT_OUT;
- break;
- case EV_READ|EV_WRITE:
- return CURL_CSELECT_IN|CURL_CSELECT_OUT;
- break;
- default:
- return 0;
- }
-}
-
-static void php_http_curlm_timeout_callback(int socket, short action, void *event_data)
-{
- php_http_client_t *context = event_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "T");
-#endif
- if (curl->useevents) {
- CURLMcode rc;
- TSRMLS_FETCH_FROM_CTX(context->ts);
-
- /* ignore and use -1,0 on timeout */
- (void) socket;
- (void) action;
-
- while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished)));
-
- if (CURLM_OK != rc) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
- }
-
- php_http_curlm_responsehandler(context);
- }
-}
-
-static void php_http_curlm_event_callback(int socket, short action, void *event_data)
-{
- php_http_client_t *context = event_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "E");
-#endif
- if (curl->useevents) {
- CURLMcode rc = CURLM_OK;
- TSRMLS_FETCH_FROM_CTX(context->ts);
-
- while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, socket, etoca(action), &curl->unfinished)));
-
- if (CURLM_OK != rc) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc));
- }
-
- php_http_curlm_responsehandler(context);
-
- /* remove timeout if there are no transfers left */
- if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- event_del(curl->timeout);
- }
- }
-}
-
-static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
-{
- php_http_client_t *context = socket_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "S");
-#endif
- if (curl->useevents) {
- int events = EV_PERSIST;
- php_http_curlm_event_t *ev = assign_data;
- TSRMLS_FETCH_FROM_CTX(context->ts);
-
- if (!ev) {
- ev = ecalloc(1, sizeof(php_http_curlm_event_t));
- ev->context = context;
- curl_multi_assign(curl->handle->multi, sock, ev);
- } else {
- event_del(&ev->evnt);
- }
-
- switch (action) {
- case CURL_POLL_IN:
- events |= EV_READ;
- break;
- case CURL_POLL_OUT:
- events |= EV_WRITE;
- break;
- case CURL_POLL_INOUT:
- events |= EV_READ|EV_WRITE;
- break;
-
- case CURL_POLL_REMOVE:
- efree(ev);
- /* no break */
- case CURL_POLL_NONE:
- return 0;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
- return -1;
- }
-
- event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context);
- event_add(&ev->evnt, NULL);
- }
-
- return 0;
-}
-
-static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
-{
- php_http_client_t *context = timer_data;
- php_http_client_curl_t *curl = context->ctx;
-
-#if DBG_EVENTS
- fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
-#endif
- if (curl->useevents) {
-
- if (timeout_ms < 0) {
- php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context);
- } else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- struct timeval timeout;
-
- 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;
{
php_http_client_curl_t *curl = h->ctx;
- if ((curl->useevents = enable)) {
- if (!curl->evbase) {
- curl->evbase = event_base_new();
+ if (enable) {
+ if (!curl->ev_ops) {
+ if (!(curl->ev_ops = php_http_client_curl_event_ops_get())) {
+ return FAILURE;
+ }
}
- if (!curl->timeout) {
- curl->timeout = ecalloc(1, sizeof(struct event));
+ if (curl->ev_ops && !curl->ev_ctx) {
+ if (!(curl->ev_ctx = curl->ev_ops->init(h))) {
+ return FAILURE;
+ }
}
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, h);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, h);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback);
} else {
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL);
- curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL);
+ if (curl->ev_ops) {
+ if (curl->ev_ctx) {
+ curl->ev_ops->dtor(&curl->ev_ctx);
+ }
+ curl->ev_ops = NULL;
+ }
}
return SUCCESS;
{
php_http_client_t *client = userdata;
- return php_http_curlm_use_eventloop(client, value && Z_BVAL_P(value));
+ if (Z_TYPE_P(value) == IS_OBJECT /* && instanceof_function */) {
+ abort();
+ }
+ return php_http_curlm_use_eventloop(client, value && z_is_true(value));
}
#endif
php_http_client_curl_t *curl = h->ctx;
TSRMLS_FETCH_FROM_CTX(h->ts);
-#if PHP_HTTP_HAVE_EVENT
- if (curl->timeout) {
- if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- event_del(curl->timeout);
- }
- efree(curl->timeout);
- curl->timeout = NULL;
+ if (curl->ev_ops) {
+ curl->ev_ops->dtor(&curl->ev_ctx);
}
- if (curl->evbase) {
- event_base_free(curl->evbase);
- curl->evbase = NULL;
- }
-#endif
curl->unfinished = 0;
php_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC);
}
}
-static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout)
-{
- if ((CURLM_OK == curl_multi_timeout(curl->handle->multi, &max_tout)) && (max_tout > 0)) {
- timeout->tv_sec = max_tout / 1000;
- timeout->tv_usec = (max_tout % 1000) * 1000;
- } else {
- timeout->tv_sec = 0;
- timeout->tv_usec = 1000;
- }
-}
-
#ifdef PHP_WIN32
# define SELECT_ERROR SOCKET_ERROR
#else
struct timeval timeout;
php_http_client_curl_t *curl = h->ctx;
-#if PHP_HTTP_HAVE_EVENT
- if (curl->useevents) {
- if (!event_initialized(curl->timeout)) {
- event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, h);
- } else if (custom_timeout && timerisset(custom_timeout)) {
- event_add(curl->timeout, custom_timeout);
- } else if (!event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
- php_http_client_curl_get_timeout(curl, 1000, &timeout);
- event_add(curl->timeout, &timeout);
- }
-
- event_base_loop(curl->evbase, EVLOOP_ONCE);
-
- return SUCCESS;
+ if (curl->ev_ops) {
+ return curl->ev_ops->wait(curl->ev_ctx, custom_timeout);
}
-#endif
FD_ZERO(&R);
FD_ZERO(&W);
{
php_http_client_curl_t *curl = h->ctx;
-#if PHP_HTTP_HAVE_EVENT
- if (curl->useevents) {
- event_base_loop(curl->evbase, EVLOOP_NONBLOCK);
- } else
-#endif
- while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle->multi, &curl->unfinished));
+ if (curl->ev_ops) {
+ curl->ev_ops->once(curl->ev_ctx);
+ } else {
+ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle->multi, &curl->unfinished));
+ }
- php_http_curlm_responsehandler(h);
+ php_http_client_curl_responsehandler(h);
return curl->unfinished;
static ZEND_RESULT_CODE php_http_client_curl_exec(php_http_client_t *h)
{
-#if PHP_HTTP_HAVE_EVENT
php_http_client_curl_t *curl = h->ctx;
-#endif
TSRMLS_FETCH_FROM_CTX(h->ts);
-#if PHP_HTTP_HAVE_EVENT
- if (curl->useevents) {
- php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
- do {
- int ev_rc = event_base_dispatch(curl->evbase);
-
-#if DBG_EVENTS
- fprintf(stderr, "%c", "X.0"[ev_rc+1]);
-#endif
+ if (curl->ev_ops) {
+ return curl->ev_ops->exec(curl->ev_ctx);
+ }
- if (ev_rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error in event_base_dispatch()");
- return FAILURE;
- }
- } while (curl->unfinished && !EG(exception));
- } else
-#endif
- {
- while (php_http_client_curl_once(h) && !EG(exception)) {
- if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
+ while (php_http_client_curl_once(h) && !EG(exception)) {
+ if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
#ifdef PHP_WIN32
- /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
+ /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "WinSock error: %d", WSAGetLastError());
#else
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
#endif
- return FAILURE;
- }
+ return FAILURE;
}
}
return &php_http_client_curl_ops;
}
+
PHP_MINIT_FUNCTION(http_client_curl)
{
curl_version_info_data *info;
#if PHP_HTTP_HAVE_CURL
+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_MINIT_FUNCTION(http_client_curl);
PHP_MSHUTDOWN_FUNCTION(http_client_curl);
#endif /* PHP_HTTP_HAVE_CURL */
--- /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> |
+ +--------------------------------------------------------------------+
+*/
+
+#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 <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;
+ 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_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);
+ 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
+
+ ZEND_ASSERT(ctx);
+
+ 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> |
+ +--------------------------------------------------------------------+
+*/
+
+#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
+
+/*
+ * 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
+ */
echo "Test\n";
+function dump($response) {
+ echo $response->getHeader("X-Req"),"\n";
+}
+
server("pipeline.inc", function($port, $stdin, $stdout, $stderr) {
/* tell the server we're about to send 3 pipelined messages */
fputs($stdin, "3\n");
$client->configure(array("pipelining" => true, "max_host_connections" => 0));
/* this is just to let curl know the server may be capable of pipelining */
- $client->enqueue(new http\Client\Request("GET", "http://localhost:$port"));
+ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port"), "dump");
$client->send();
- $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/1"));
- $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/2"));
- $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/3"));
+ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/1"), "dump");
+ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/2"), "dump");
+ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/3"), "dump");
$client->send();
-
- while (($response = $client->getResponse())) {
- echo $response;
- }
});
?>
===DONE===
--EXPECT--
Test
-HTTP/1.1 200 OK
-X-Req: /3
-Etag: ""
-X-Original-Transfer-Encoding: chunked
-HTTP/1.1 200 OK
-X-Req: /2
-Etag: ""
-X-Original-Transfer-Encoding: chunked
-HTTP/1.1 200 OK
-X-Req: /1
-Etag: ""
-X-Original-Transfer-Encoding: chunked
-HTTP/1.1 200 OK
-X-Req: /
-Etag: ""
-X-Original-Transfer-Encoding: chunked
+/
+/1
+/2
+/3
===DONE===
$client->setOptions([
"protocol" => http\Client\Curl\HTTP_VERSION_2_0,
"ssl" => [
- "cainfo" => __DIR__."/helper/http2.crt",
+ "cafile" => __DIR__."/helper/http2.crt",
]
]);
$client->enqueue(new http\Client\Request("GET", "https://localhost:$port"));
/* pipelined messages */
$req = array();
for ($i=0; $i < $count; ++ $i) {
- $req[] = new http\Message($client, false);
- logger("Read request no. %d from client %d", $i+1, (int) $client);
+ $req[] = $m = new http\Message($client, false);
+ logger("Read request no. %d from client %d (%s)", $i+1, (int) $client, $m->getRequestUrl());
}
foreach ($req as $i => $msg) {
respond($client, $msg);
}
}
-function skip_http2_test($message = "skip need http2 support (nghttpd in PATH)\n") {
- if (defined("http\\Client\\Curl\\HTTP_VERSION_2_0")) {
- foreach (explode(":", $_ENV["PATH"]) as $path) {
- if (is_executable($path . "/nghttpd")) {
- return;
- }
+function skip_http2_test($message = "skip need http2 support") {
+ if (!defined("http\\Client\\Curl\\HTTP_VERSION_2_0")) {
+ die("$message (HTTP_VERSION_2_0)\n");
+ }
+ if (!(http\Client\Curl\FEATURES & http\Client\Curl\Features\HTTP2)) {
+ die("$message (FEATURES & HTTP2)\n");
+ }
+ foreach (explode(":", $_ENV["PATH"]) as $path) {
+ if (is_executable($path . "/nghttpd")) {
+ return;
}
}
- die($message);
+ die("$message (nghttpd in PATH)\n");
}
\ No newline at end of file