From 1ac722a1169ffe0f804f8d30a79c2f270d0d7999 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 21 Jun 2016 08:50:14 +0200 Subject: [PATCH] Add http\Client::setDebug(callable $debug) and constants Returns: * http\Client, self Params: * callable $debug as function(http\Client $c, http\Client\Request $r, int $type, string $data) Added constants (used for the $type bitmask parameter of the callback): * http\Client::DEBUG_INFO (informational text) * http\Client::DEBUG_IN (received data) * http\Client::DEBUG_OUT (sent data) * http\Client::DEBUG_HEADER (headers) * http\Client::DEBUG_BODY (body) * http\Client::DEBUG_SSL (SSL data) E.g. incoming headers would have the bitmask (http\Client::DEBUG_IN|http\Client::DEBUG_HEADER) set in the $type parameter. Messages of type http\Client::DEBUG_INFO contain human readable text like "Proxy CONNECT connection closed\n". --- src/php_http_client.c | 77 ++++++++++++++++++++++++++++++++++++++ src/php_http_client.h | 16 ++++++++ src/php_http_client_curl.c | 29 +++++++++++++- 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/php_http_client.c b/src/php_http_client.c index 0463b7a..f1b1fc5 100644 --- a/src/php_http_client.c +++ b/src/php_http_client.c @@ -204,6 +204,8 @@ void php_http_client_dtor(php_http_client_t *h) if (h->ops->dtor) { h->ops->dtor(h); } + h->callback.debug.func = NULL; + h->callback.debug.arg = NULL; php_resource_factory_free(&h->rf); } @@ -329,6 +331,11 @@ void php_http_client_object_free(void *object TSRMLS_DC) php_http_client_object_t *o = (php_http_client_object_t *) object; php_http_client_free(&o->client); + if (o->debug.fci.size > 0) { + zend_fcall_info_args_clear(&o->debug.fci, 1); + zval_ptr_dtor(&o->debug.fci.function_name); + o->debug.fci.size = 0; + } php_http_object_method_dtor(&o->notify); php_http_object_method_free(&o->update); zend_object_std_dtor((zend_object *) o TSRMLS_CC); @@ -491,6 +498,36 @@ static void handle_progress(void *arg, php_http_client_t *client, php_http_clien zval_ptr_dtor(&zprogress); } +static void handle_debug(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, unsigned type, const char *data, size_t size) +{ + zval *ztype, *zdata, *zreq, *zclient; + php_http_client_object_t *client_obj = arg; + zend_error_handling zeh; + TSRMLS_FETCH_FROM_CTX(client->ts); + + MAKE_STD_ZVAL(zclient); + ZVAL_OBJVAL(zclient, client_obj->zv, 1); + MAKE_STD_ZVAL(zreq); + ZVAL_OBJVAL(zreq, ((php_http_message_object_t *) e->opaque)->zv, 1); + MAKE_STD_ZVAL(ztype); + ZVAL_LONG(ztype, type); + MAKE_STD_ZVAL(zdata); + ZVAL_STRINGL(zdata, data, size, 1); + + zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); + if (SUCCESS == zend_fcall_info_argn(&client_obj->debug.fci TSRMLS_CC, 4, &zclient, &zreq, &ztype, &zdata)) { + zend_fcall_info_call(&client_obj->debug.fci, &client_obj->debug.fcc, NULL, NULL TSRMLS_CC); + zend_fcall_info_args_clear(&client_obj->debug.fci, 0); + } + zend_restore_error_handling(&zeh TSRMLS_CC); + + zval_ptr_dtor(&zclient); + zval_ptr_dtor(&zreq); + zval_ptr_dtor(&ztype); + zval_ptr_dtor(&zdata); + +} + static void response_dtor(void *data) { php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data; @@ -1213,6 +1250,38 @@ static PHP_METHOD(HttpClient, getAvailableConfiguration) } } +ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setDebug, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 1) +ZEND_END_ARG_INFO(); +static PHP_METHOD(HttpClient, setDebug) +{ + zend_fcall_info fci; + zend_fcall_info_cache fcc; + php_http_client_object_t *client_obj; + + fci.size = 0; + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|f", &fci, &fcc), invalid_arg, return); + + client_obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + if (client_obj->debug.fci.size > 0) { + zval_ptr_dtor(&client_obj->debug.fci.function_name); + client_obj->debug.fci.size = 0; + } + if (fci.size > 0) { + memcpy(&client_obj->debug.fci, &fci, sizeof(fci)); + memcpy(&client_obj->debug.fcc, &fcc, sizeof(fcc)); + Z_ADDREF_P(fci.function_name); + client_obj->client->callback.debug.func = handle_debug; + client_obj->client->callback.debug.arg = client_obj; + } else { + client_obj->client->callback.debug.func = NULL; + client_obj->client->callback.debug.arg = NULL; + } + + RETVAL_ZVAL(getThis(), 1, 0); +} + static zend_function_entry php_http_client_methods[] = { PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC) @@ -1245,6 +1314,7 @@ static zend_function_entry php_http_client_methods[] = { PHP_ME(HttpClient, getAvailableDrivers, ai_HttpClient_getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME(HttpClient, getAvailableOptions, ai_HttpClient_getAvailableOptions, ZEND_ACC_PUBLIC) PHP_ME(HttpClient, getAvailableConfiguration, ai_HttpClient_getAvailableConfiguration, ZEND_ACC_PUBLIC) + PHP_ME(HttpClient, setDebug, ai_HttpClient_setDebug, ZEND_ACC_PUBLIC) EMPTY_FUNCTION_ENTRY }; @@ -1263,6 +1333,13 @@ PHP_MINIT_FUNCTION(http_client) zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED TSRMLS_CC); zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_INFO"), PHP_HTTP_CLIENT_DEBUG_INFO TSRMLS_CC); + zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_IN"), PHP_HTTP_CLIENT_DEBUG_IN TSRMLS_CC); + zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_OUT"), PHP_HTTP_CLIENT_DEBUG_OUT TSRMLS_CC); + zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_HEADER"), PHP_HTTP_CLIENT_DEBUG_HEADER TSRMLS_CC); + zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_BODY"), PHP_HTTP_CLIENT_DEBUG_BODY TSRMLS_CC); + zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_SSL"), PHP_HTTP_CLIENT_DEBUG_SSL TSRMLS_CC); + zend_hash_init(&php_http_client_drivers, 2, NULL, NULL, 1); return SUCCESS; diff --git a/src/php_http_client.h b/src/php_http_client.h index f4a5b59..ecaa304 100644 --- a/src/php_http_client.h +++ b/src/php_http_client.h @@ -89,6 +89,14 @@ typedef struct php_http_client_progress_state { typedef ZEND_RESULT_CODE (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **response); typedef void (*php_http_client_progress_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state); +typedef void (*php_http_client_debug_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, unsigned type, const char *data, size_t size); + +#define PHP_HTTP_CLIENT_DEBUG_INFO 0x00 +#define PHP_HTTP_CLIENT_DEBUG_IN 0x01 +#define PHP_HTTP_CLIENT_DEBUG_OUT 0x02 +#define PHP_HTTP_CLIENT_DEBUG_HEADER 0x10 +#define PHP_HTTP_CLIENT_DEBUG_BODY 0x20 +#define PHP_HTTP_CLIENT_DEBUG_SSL 0x40 typedef struct php_http_client { void *ctx; @@ -104,6 +112,10 @@ typedef struct php_http_client { php_http_client_progress_callback_t func; void *arg; } progress; + struct { + php_http_client_debug_callback_t func; + void *arg; + } debug; } callback; zend_llist requests; @@ -123,6 +135,10 @@ typedef struct php_http_client_object { long iterator; php_http_object_method_t *update; php_http_object_method_t notify; + struct { + zend_fcall_info fci; + zend_fcall_info_cache fcc; + } debug; } php_http_client_object_t; PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); diff --git a/src/php_http_client_curl.c b/src/php_http_client_curl.c index 863b342..18d75d7 100644 --- a/src/php_http_client_curl.c +++ b/src/php_http_client_curl.c @@ -221,6 +221,7 @@ static int php_http_curle_seek_callback(void *userdata, curl_off_t offset, int o static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx) { php_http_client_curl_handler_t *h = ctx; + unsigned utype = PHP_HTTP_CLIENT_DEBUG_INFO; /* catch progress */ switch (type) { @@ -264,20 +265,43 @@ static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress); } break; + case CURLINFO_HEADER_OUT: - case CURLINFO_DATA_OUT: + utype |= PHP_HTTP_CLIENT_DEBUG_HEADER; + goto data_out; + case CURLINFO_SSL_DATA_OUT: + utype |= PHP_HTTP_CLIENT_DEBUG_SSL; + goto data_out; + + case CURLINFO_DATA_OUT: + data_out: + utype |= PHP_HTTP_CLIENT_DEBUG_OUT; h->progress.info = "send"; break; + case CURLINFO_HEADER_IN: - case CURLINFO_DATA_IN: + utype |= PHP_HTTP_CLIENT_DEBUG_HEADER; + goto data_in; + case CURLINFO_SSL_DATA_IN: + utype |= PHP_HTTP_CLIENT_DEBUG_SSL; + goto data_in; + + case CURLINFO_DATA_IN: + data_in: + utype |= PHP_HTTP_CLIENT_DEBUG_IN; h->progress.info = "receive"; break; + default: break; } + if (h->client->callback.debug.func) { + h->client->callback.debug.func(h->client->callback.debug.arg, h->client, &h->queue, utype, data, length); + } + #if 0 /* debug */ _dpf(type, data, length); @@ -2028,6 +2052,7 @@ static void php_http_client_curl_dtor(php_http_client_t *h) if (curl->ev_ops) { curl->ev_ops->dtor(&curl->ev_ctx); + curl->ev_ops = NULL; } curl->unfinished = 0; -- 2.30.2