Fix #50
[m6w6/ext-http] / src / php_http_client_curl.c
index d3f5200c141921bc6dbf922fdc9f83f6ff6c1a06..1ec6624cc21a07b7e3d6957b398621b393ff989d 100644 (file)
@@ -13,6 +13,7 @@
 #include "php_http_api.h"
 #include "php_http_client.h"
 #include "php_http_client_curl_event.h"
+#include "php_http_client_curl_user.h"
 
 #if PHP_HTTP_HAVE_CURL
 
@@ -181,22 +182,19 @@ static int php_http_curle_progress_callback(void *ctx, double dltotal, double dl
 #endif
 {
        php_http_client_curl_handler_t *h = ctx;
-       zend_bool update = 0;
 
        if (h->progress.dl.total != dltotal
        ||      h->progress.dl.now != dlnow
        ||      h->progress.ul.total != ultotal
        ||      h->progress.ul.now != ulnow
        ) {
-               update = 1;
-
                h->progress.dl.total = dltotal;
                h->progress.dl.now = dlnow;
                h->progress.ul.total = ultotal;
                h->progress.ul.now = ulnow;
        }
 
-       if (update && h->client->callback.progress.func) {
+       if (h->client->callback.progress.func) {
                h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
        }
 
@@ -220,6 +218,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) {
@@ -263,20 +262,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);
@@ -667,6 +689,27 @@ void php_http_client_curl_responsehandler(php_http_client_t *context)
        }
 }
 
+void php_http_client_curl_loop(php_http_client_t *client, curl_socket_t s, int curl_action)
+{
+       CURLMcode rc;
+       php_http_client_curl_t *curl = client->ctx;
+       TSRMLS_FETCH_FROM_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(client);
+}
+
 /* curl options */
 
 static php_http_options_t php_http_curle_options, php_http_curlm_options;
@@ -1534,22 +1577,17 @@ static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_
 }
 #endif
 
-#if PHP_HTTP_HAVE_EVENT
-static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, zend_bool enable)
+static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, php_http_client_curl_ops_t *ev_ops, zval *init_data)
 {
        php_http_client_curl_t *curl = h->ctx;
+       void *ev_ctx;
 
-       if (enable) {
-               if (!curl->ev_ops) {
-                       if (!(curl->ev_ops = php_http_client_curl_event_ops_get())) {
-                               return FAILURE;
-                       }
-               }
-               if (curl->ev_ops && !curl->ev_ctx) {
-                       if (!(curl->ev_ctx = curl->ev_ops->init(h))) {
-                               return FAILURE;
-                       }
+       if (ev_ops) {
+               if (!(ev_ctx = ev_ops->init(h, init_data))) {
+                       return FAILURE;
                }
+               curl->ev_ctx = ev_ctx;
+               curl->ev_ops = ev_ops;
        } else {
                if (curl->ev_ops) {
                        if (curl->ev_ctx) {
@@ -1565,13 +1603,19 @@ static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h
 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);
 
-       if (Z_TYPE_P(value) == IS_OBJECT /* && instanceof_function */) {
-               abort();
+       if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_client_curl_user_class_entry TSRMLS_CC)) {
+               ev_ops = php_http_client_curl_user_ops_get();
+#if PHP_HTTP_HAVE_EVENT
+       } else if (value && z_is_true(value)) {
+               ev_ops = php_http_client_curl_event_ops_get();
+#endif
        }
-       return php_http_curlm_use_eventloop(client, value && z_is_true(value));
+
+       return php_http_curlm_use_eventloop(client, ev_ops, value);
 }
-#endif
 
 static ZEND_RESULT_CODE php_http_curlm_option_set_share_cookies(php_http_option_t *opt, zval *value, void *userdata)
 {
@@ -1661,11 +1705,9 @@ static void php_http_curlm_options_init(php_http_options_t *registry TSRMLS_DC)
        }
 #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))) {
                opt->setter = php_http_curlm_option_set_share_cookies;
@@ -2007,6 +2049,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;
 
@@ -2122,6 +2165,11 @@ static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_h
        php_http_client_curl_handler_t *handler = enqueue->opaque;
        TSRMLS_FETCH_FROM_CTX(h->ts);
 
+       if (h->callback.depth) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not dequeue request while executing callbacks");
+               return FAILURE;
+       }
+
        php_http_client_curl_handler_clear(handler);
        if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) {
                zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue);
@@ -2238,7 +2286,9 @@ static ZEND_RESULT_CODE php_http_client_curl_setopt(php_http_client_t *h, php_ht
 
                case PHP_HTTP_CLIENT_OPT_USE_EVENTS:
 #if PHP_HTTP_HAVE_EVENT
-                       return php_http_curlm_use_eventloop(h, *(zend_bool *) arg);
+                       return php_http_curlm_use_eventloop(h, (*(zend_bool *) arg)
+                                       ? php_http_client_curl_event_ops_get()
+                                       : NULL, NULL);
                        break;
 #endif