- draft: implement curl_multi as HttpRequestPool
authorMichael Wallner <mike@php.net>
Tue, 7 Jun 2005 11:27:39 +0000 (11:27 +0000)
committerMichael Wallner <mike@php.net>
Tue, 7 Jun 2005 11:27:39 +0000 (11:27 +0000)
12 files changed:
Makefile.frag
config.m4
config.w32
http.c
http_methods.c
http_request_api.c
http_request_object.c
http_requestpool_object.c [new file with mode: 0644]
php_http_request_api.h
php_http_request_object.h
php_http_requestpool_object.h [new file with mode: 0644]
php_http_std_defs.h

index e56cc68..773c9fa 100644 (file)
@@ -17,6 +17,7 @@ HTTP_HEADER_FILES= \
        php_http_auth_api.h \
        php_http_exception_object.h \
        php_http_request_object.h \
+       php_http_requestpool_object.h \
        php_http_url_api.h
 
 install-http-headers:
index 58f290a..4f791d7 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -73,7 +73,7 @@ dnl DONE
 dnl ----
        PHP_HTTP_SOURCES="missing.c http.c http_functions.c http_methods.c phpstr/phpstr.c \
                http_util_object.c http_message_object.c http_request_object.c \
-               http_response_object.c http_exception_object.c \
+               http_response_object.c http_exception_object.c http_requestpool_object.c \
                http_api.c http_auth_api.c http_cache_api.c http_request_api.c http_date_api.c \
                http_headers_api.c http_message_api.c http_send_api.c http_url_api.c"
        PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, [$ext_shared])
index f539b40..a5a9b74 100644 (file)
@@ -7,7 +7,7 @@ ARG_WITH("http-curl-zend-mm", "wheter ext/http's curl should use zend mm");
 if (PHP_HTTP != "no") {
        EXTENSION("http",
                "missing.c http.c http_functions.c http_methods.c http_exception_object.c "+
-               "http_util_object.c http_message_object.c "+
+               "http_util_object.c http_message_object.c http_requestpool_object.c "+
                "http_request_object.c http_response_object.c "+
                "http_api.c http_auth_api.c http_cache_api.c "+
                "http_request_api.c http_date_api.c http_headers_api.c "+
@@ -29,4 +29,4 @@ if (PHP_HTTP != "no") {
     } else {
         WARNING("curl convenience functions not enabled; libraries and headers not found");
     }
-}
\ No newline at end of file
+}
diff --git a/http.c b/http.c
index a09fa61..575fc3c 100644 (file)
--- a/http.c
+++ b/http.c
@@ -46,6 +46,7 @@
 #      include "php_http_response_object.h"
 #      ifdef HTTP_HAVE_CURL
 #              include "php_http_request_object.h"
+#              include "php_http_requestpool_object.h"
 #      endif
 #      include "php_http_exception_object.h"
 #endif
@@ -184,6 +185,7 @@ static inline void http_globals_free(zend_http_globals *G)
        STR_FREE(G->send.content_type);
        STR_FREE(G->send.unquoted_etag);
        zend_hash_destroy(&G->request.methods.custom);
+       zend_llist_clean(&G->request.curl.copies);
 }
 /* }}} */
 
@@ -242,6 +244,7 @@ PHP_MINIT_FUNCTION(http)
        http_response_object_init();
 #      ifdef HTTP_HAVE_CURL
        http_request_object_init();
+       http_requestpool_object_init();
 #      endif /* HTTP_HAVE_CURL */
        http_exception_object_init();
 #endif /* ZEND_ENGINE_2 */
index a8e0560..cf8f25d 100644 (file)
@@ -36,6 +36,7 @@
 #include "php_http_message_object.h"
 #include "php_http_response_object.h"
 #include "php_http_request_object.h"
+#include "php_http_requestpool_object.h"
 #include "php_http_exception_object.h"
 
 #ifdef ZEND_ENGINE_2
@@ -1796,11 +1797,11 @@ PHP_METHOD(HttpRequest, setPutFile)
        char *file;
        int file_len;
        getObject(http_request_object, obj);
-       
+
        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &file_len)) {
                RETURN_FALSE;
        }
-       
+
        UPD_PROP(obj, string, putFile, file);
        RETURN_TRUE;
 }
@@ -2111,130 +2112,102 @@ PHP_METHOD(HttpRequest, getResponseMessage)
 PHP_METHOD(HttpRequest, send)
 {
        STATUS status = FAILURE;
-       zval *meth, *URL, *qdata, *opts, *info, *resp;
-       char *request_uri;
+       http_request_body body = {0};
        getObject(http_request_object, obj);
 
        NO_ARGS;
 
        SET_EH_THROW_HTTP();
 
-       if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
-               http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl");
+       if (obj->attached) {
+               http_error(E_WARNING, HTTP_E_CURL, "You cannot call HttpRequest::send() while attached to an HttpRequestPool");
                RETURN_FALSE;
        }
 
-       meth  = GET_PROP(obj, method);
-       URL   = GET_PROP(obj, url);
-       qdata = GET_PROP(obj, queryData);
-       opts  = GET_PROP(obj, options);
-       info  = GET_PROP(obj, responseInfo);
-       resp  = GET_PROP(obj, responseData);
-
-       // HTTP_URI_MAXLEN+1 long char *
-       if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) {
-               RETURN_FALSE;
+       if (SUCCESS == (status = http_request_object_requesthandler(obj, getThis(), &body))) {
+               zval *info = GET_PROP(obj, responseInfo);
+               status = http_request_exec(obj->ch, Z_ARRVAL_P(info));
+               SET_PROP(obj, responseInfo, info);
        }
+       http_request_body_dtor(&body);
 
-       if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
-               if (!strchr(request_uri, '?')) {
-                       strcat(request_uri, "?");
-               } else {
-                       strcat(request_uri, "&");
-               }
-               strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
+       /* final data handling */
+       if (SUCCESS == status) {
+               status = http_request_object_responsehandler(obj, getThis(), NULL);
        }
 
-       switch (Z_LVAL_P(meth))
-       {
-               case HTTP_GET:
-               case HTTP_HEAD:
-                       status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, NULL, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
-               break;
-
-               case HTTP_PUT:
-               {
-                       http_request_body body;
-                       php_stream *stream;
-                       php_stream_statbuf ssb;
-                       zval *file = GET_PROP(obj, putFile);
-
-                       if (    (stream = php_stream_open_wrapper(Z_STRVAL_P(file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) &&
-                                       !php_stream_stat(stream, &ssb)) {
-                               body.type = HTTP_REQUEST_BODY_UPLOADFILE;
-                               body.data = stream;
-                               body.size = ssb.sb.st_size;
-
-                               status = http_put_ex(obj->ch, request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
-                               http_request_body_dtor(&body);
-                       } else {
-                               status = FAILURE;
-                       }
-               }
-               break;
-
-               case HTTP_POST:
-               {
-                       http_request_body body;
-                       zval *fields = GET_PROP(obj, postFields), *files = GET_PROP(obj, postFiles);
+       SET_EH_NORMAL();
+       RETURN_SUCCESS(status);
+}
+/* }}} */
 
-                       if (SUCCESS == (status = http_request_body_fill(&body, Z_ARRVAL_P(fields), Z_ARRVAL_P(files)))) {
-                               status = http_post_ex(obj->ch, request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
-                               http_request_body_dtor(&body);
-                       }
-               }
-               break;
+/* {{{ HttpRequestPool */
 
-               default:
-               {
-                       http_request_body body;
-                       zval *post = GET_PROP(obj, postData);
+/* {{{ proto void HttpRequestPool::__construct(void)
+ *
+ * Instantiate a new HttpRequestPool object.
+ */
+PHP_METHOD(HttpRequestPool, __construct)
+{
+       NO_ARGS;
+}
+/* }}} */
 
-                       body.type = HTTP_REQUEST_BODY_CSTRING;
-                       body.data = Z_STRVAL_P(post);
-                       body.size = Z_STRLEN_P(post);
+/* {{{ proto bool HttpRequestPool::attach(HttpRequest request)
+ *
+ * Attach an HttpRequest object to this HttpRequestPool.
+ * NOTE: set all options prior attaching!
+ */
+PHP_METHOD(HttpRequestPool, attach)
+{
+       zval *request;
+       STATUS status = FAILURE;
+       getObject(http_requestpool_object, obj);
 
-                       status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
-               }
-               break;
+       SET_EH_THROW_HTTP();
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
+               status = http_request_pool_attach(&obj->pool, request);
        }
+       SET_EH_NORMAL();
+       RETURN_SUCCESS(status);
+}
+/* }}} */
 
-       efree(request_uri);
-
-       /* final data handling */
-       if (status == SUCCESS) {
-               http_message *msg;
-
-               if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
-                       zval *headers, *message;
-                       char *body;
-                       size_t body_len;
-
-                       UPD_PROP(obj, long, responseCode, msg->info.response.code);
-
-                       MAKE_STD_ZVAL(headers)
-                       array_init(headers);
-
-                       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
-                       phpstr_data(PHPSTR(msg), &body, &body_len);
-
-                       add_assoc_zval(resp, "headers", headers);
-                       add_assoc_stringl(resp, "body", body, body_len, 0);
+/* {{{ proto bool HttpRequestPool::detach(HttpRequest request)
+ *
+ * Detach an HttpRequest object from this HttpRequestPool.
+ */
+PHP_METHOD(HttpRequestPool, detach)
+{
+       zval *request;
+       STATUS status = FAILURE;
+       getObject(http_requestpool_object, obj);
 
-                       message = GET_PROP(obj, responseMessage);
-                       zval_dtor(message);
-                       Z_TYPE_P(message)  = IS_OBJECT;
-                       message->value.obj = http_message_object_from_msg(msg);
-                       SET_PROP(obj, responseMessage, message);
-               } else {
-                       status = FAILURE;
-               }
+       SET_EH_THROW_HTTP();
+       if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
+               status = http_request_pool_detach(&obj->pool, request);
        }
-
        SET_EH_NORMAL();
        RETURN_SUCCESS(status);
 }
 /* }}} */
+
+/* {{{ proto bool HttpRequestPool::send()
+ *
+ * Send all attached HttpRequest objects in parallel.
+ */
+PHP_METHOD(HttpRequestPool, send)
+{
+       getObject(http_requestpool_object, obj);
+
+       NO_ARGS;
+
+       RETURN_SUCCESS(http_request_pool_send(&obj->pool));
+}
+/* }}} */
+
+/* }}} */
+
 /* }}} */
 #endif /* HTTP_HAVE_CURL */
 
index 534542f..8f2cb37 100644 (file)
@@ -32,6 +32,8 @@
 #include "php_http_std_defs.h"
 #include "php_http_api.h"
 #include "php_http_request_api.h"
+#include "php_http_request_object.h"
+#include "php_http_requestpool_object.h"
 #include "php_http_url_api.h"
 
 ZEND_EXTERN_MODULE_GLOBALS(http)
@@ -48,7 +50,7 @@ ZEND_EXTERN_MODULE_GLOBALS(http)
                { \
                        char *c; \
                        if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_ ##I, &c)) { \
-                               add_assoc_string(&array, pretty_key(http_curl_copystr(#X), sizeof(#X)-1, 0, 0), c ? c : "", 1); \
+                               add_assoc_string(&array, pretty_key(http_request_copystr(#X), sizeof(#X)-1, 0, 0), c ? c : "", 1); \
                        } \
                } \
                break; \
@@ -57,7 +59,7 @@ ZEND_EXTERN_MODULE_GLOBALS(http)
                { \
                        double d; \
                        if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_ ##I, &d)) { \
-                               add_assoc_double(&array, pretty_key(http_curl_copystr(#X), sizeof(#X)-1, 0, 0), d); \
+                               add_assoc_double(&array, pretty_key(http_request_copystr(#X), sizeof(#X)-1, 0, 0), d); \
                        } \
                } \
                break; \
@@ -66,7 +68,7 @@ ZEND_EXTERN_MODULE_GLOBALS(http)
                { \
                        long l; \
                        if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_ ##I, &l)) { \
-                               add_assoc_long(&array, pretty_key(http_curl_copystr(#X), sizeof(#X)-1, 0, 0), l); \
+                               add_assoc_long(&array, pretty_key(http_request_copystr(#X), sizeof(#X)-1, 0, 0), l); \
                        } \
                } \
                break; \
@@ -79,7 +81,7 @@ ZEND_EXTERN_MODULE_GLOBALS(http)
 #define HTTP_CURL_OPT_STRING_EX(keyname, optname) \
        if (!strcasecmp(key, #keyname)) { \
                convert_to_string_ex(param); \
-               HTTP_CURL_OPT(optname, http_curl_copystr(Z_STRVAL_PP(param))); \
+               HTTP_CURL_OPT(optname, http_request_copystr(Z_STRVAL_PP(param))); \
                key = NULL; \
                continue; \
        }
@@ -96,8 +98,6 @@ ZEND_EXTERN_MODULE_GLOBALS(http)
 
 
 static const char *const http_request_methods[HTTP_MAX_REQUEST_METHOD + 1];
-#define http_curl_copystr(s) _http_curl_copystr((s) TSRMLS_CC)
-static inline char *_http_curl_copystr(const char *str TSRMLS_DC);
 #define http_curl_getopt(o, k, t) _http_curl_getopt_ex((o), (k), sizeof(k), (t) TSRMLS_CC)
 #define http_curl_getopt_ex(o, k, l, t) _http_curl_getopt_ex((o), (k), (l), (t) TSRMLS_CC)
 static inline zval *_http_curl_getopt_ex(HashTable *options, char *key, size_t keylen, int type TSRMLS_DC);
@@ -106,6 +106,27 @@ static size_t http_curl_read_callback(void *, size_t, size_t, void *);
 static int http_curl_progress_callback(void *, double, double, double, double);
 static int http_curl_debug_callback(CURL *, curl_infotype, char *, size_t, void *);
 
+static void http_request_pool_freebody(http_request_body **body);
+static void http_request_pool_responsehandler(zval **req TSRMLS_DC);
+static inline STATUS http_request_pool_select(http_request_pool *pool);
+static inline void http_request_pool_perform(http_request_pool *pool);
+
+/* {{{ char *http_request_copystr(char *) */
+PHP_HTTP_API char *_http_request_copystr(const char *str TSRMLS_DC)
+{
+       char *new_str = estrdup(str);
+       zend_llist_add_element(&HTTP_G(request).curl.copies, &new_str);
+       return new_str;
+}
+/* }}} */
+
+/* {{{ http_request_body *http_request_body_new() */
+PHP_HTTP_API http_request_body *_http_request_body_new(TSRMLS_D)
+{
+       http_request_body *body = ecalloc(1, sizeof(http_request_body));
+       return body;
+}
+/* }}} */
 
 /* {{{ STATUS http_request_body_fill(http_request_body *body, HashTable *, HashTable *) */
 PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files TSRMLS_DC)
@@ -186,50 +207,58 @@ PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *
 /* {{{ void http_request_body_dtor(http_request_body *) */
 PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC)
 {
-       switch (body->type)
-       {
-               case HTTP_REQUEST_BODY_CSTRING:
-                       efree(body->data);
-               break;
+       if (body) {
+               switch (body->type)
+               {
+                       case HTTP_REQUEST_BODY_CSTRING:
+                               if (body->data) {
+                                       efree(body->data);
+                               }
+                       break;
 
-               case HTTP_REQUEST_BODY_CURLPOST:
-                       curl_formfree(body->data);
-               break;
+                       case HTTP_REQUEST_BODY_CURLPOST:
+                               curl_formfree(body->data);
+                       break;
 
-               case HTTP_REQUEST_BODY_UPLOADFILE:
-                       php_stream_close(body->data);
-               break;
+                       case HTTP_REQUEST_BODY_UPLOADFILE:
+                               php_stream_close(body->data);
+                       break;
+               }
        }
 }
 /* }}} */
 
-/* {{{ STATUS http_request_ex(CURL *, http_request_method, char *, http_request_body, HashTable, HashTable, phpstr *) */
-PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const char *url, http_request_body *body, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC)
+/* {{{ void http_request_body_free(http_request_body *) */
+PHP_HTTP_API void _http_request_body_free(http_request_body *body TSRMLS_DC)
+{
+       if (body) {
+               http_request_body_dtor(body);
+               efree(body);
+       }
+}
+/* }}} */
+
+/* {{{ STATUS http_request_init(CURL *, http_request_method, char *, http_request_body *, HashTable *, phpstr *) */
+PHP_HTTP_API STATUS _http_request_init(CURL *ch, http_request_method meth, const char *url, http_request_body *body, HashTable *options, phpstr *response TSRMLS_DC)
 {
-       CURLcode result = CURLE_OK;
-       STATUS status = SUCCESS;
-       zend_bool clean_curl = 0, range_req = 0;
        zval *zoption;
+       zend_bool range_req = 0;
 
-       /* check/init CURL handle */
-       if (ch) {
+       /* reset CURL handle */
 #if LIBCURL_VERSION_NUM >= 0x070c01
-               curl_easy_reset(ch);
+       curl_easy_reset(ch);
 #endif
-       } else {
-               if (ch = curl_easy_init()) {
-                       clean_curl = 1;
-               } else {
-                       http_error(E_WARNING, HTTP_E_CURL, "Could not initialize curl");
-                       return FAILURE;
-               }
-       }
 
        /* set options */
        if (url) {
                HTTP_CURL_OPT(URL, url);
        }
 
+       if (response) {
+               HTTP_CURL_OPT(WRITEDATA, response);
+               HTTP_CURL_OPT(WRITEHEADER, response);
+       }
+
        HTTP_CURL_OPT(HEADER, 0);
        HTTP_CURL_OPT(FILETIME, 1);
        HTTP_CURL_OPT(AUTOREFERER, 1);
@@ -237,11 +266,6 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
        HTTP_CURL_OPT(WRITEFUNCTION, http_curl_write_callback);
        HTTP_CURL_OPT(HEADERFUNCTION, http_curl_write_callback);
 
-       if (response) {
-               HTTP_CURL_OPT(WRITEDATA, response);
-               HTTP_CURL_OPT(WRITEHEADER, response);
-       }
-
 #if defined(ZTS) && (LIBCURL_VERSION_NUM >= 0x070a00)
        HTTP_CURL_OPT(NOSIGNAL, 1);
 #endif
@@ -269,14 +293,14 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
 
        /* proxy */
        if (zoption = http_curl_getopt(options, "proxyhost", IS_STRING)) {
-               HTTP_CURL_OPT(PROXY, http_curl_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(PROXY, http_request_copystr(Z_STRVAL_P(zoption)));
                /* port */
                if (zoption = http_curl_getopt(options, "proxyport", IS_LONG)) {
                        HTTP_CURL_OPT(PROXYPORT, Z_LVAL_P(zoption));
                }
                /* user:pass */
                if (zoption = http_curl_getopt(options, "proxyauth", IS_STRING)) {
-                       HTTP_CURL_OPT(PROXYUSERPWD, http_curl_copystr(Z_STRVAL_P(zoption)));
+                       HTTP_CURL_OPT(PROXYUSERPWD, http_request_copystr(Z_STRVAL_P(zoption)));
                }
 #if LIBCURL_VERSION_NUM >= 0x070a07
                /* auth method */
@@ -288,7 +312,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
 
        /* outgoing interface */
        if (zoption = http_curl_getopt(options, "interface", IS_STRING)) {
-               HTTP_CURL_OPT(INTERFACE, http_curl_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(INTERFACE, http_request_copystr(Z_STRVAL_P(zoption)));
        }
 
        /* another port */
@@ -298,7 +322,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
 
        /* auth */
        if (zoption = http_curl_getopt(options, "httpauth", IS_STRING)) {
-               HTTP_CURL_OPT(USERPWD, http_curl_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(USERPWD, http_request_copystr(Z_STRVAL_P(zoption)));
        }
 #if LIBCURL_VERSION_NUM >= 0x070a06
        if (zoption = http_curl_getopt(options, "httpauthtype", IS_LONG)) {
@@ -309,7 +333,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
        /* compress, empty string enables deflate and gzip */
        if (zoption = http_curl_getopt(options, "compress", IS_BOOL)) {
                if (Z_LVAL_P(zoption)) {
-                       HTTP_CURL_OPT(ENCODING, http_curl_copystr(""));
+                       HTTP_CURL_OPT(ENCODING, http_request_copystr(""));
                }
        }
 
@@ -326,12 +350,12 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
 
        /* referer */
        if (zoption = http_curl_getopt(options, "referer", IS_STRING)) {
-               HTTP_CURL_OPT(REFERER, http_curl_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(REFERER, http_request_copystr(Z_STRVAL_P(zoption)));
        }
 
        /* useragent, default "PECL::HTTP/version (PHP/version)" */
        if (zoption = http_curl_getopt(options, "useragent", IS_STRING)) {
-               HTTP_CURL_OPT(USERAGENT, http_curl_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(USERAGENT, http_request_copystr(Z_STRVAL_P(zoption)));
        } else {
                HTTP_CURL_OPT(USERAGENT, "PECL::HTTP/" HTTP_PEXT_VERSION " (PHP/" PHP_VERSION ")");
        }
@@ -348,7 +372,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
                                if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void **) &header_val)) {
                                        char header[1024] = {0};
                                        snprintf(header, 1023, "%s: %s", header_key, Z_STRVAL_PP(header_val));
-                                       headers = curl_slist_append(headers, http_curl_copystr(header));
+                                       headers = curl_slist_append(headers, http_request_copystr(header));
                                }
 
                                /* reset */
@@ -381,15 +405,15 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
 
                if (qstr->used) {
                        phpstr_fix(qstr);
-                       HTTP_CURL_OPT(COOKIE, http_curl_copystr(qstr->data));
+                       HTTP_CURL_OPT(COOKIE, http_request_copystr(qstr->data));
                }
                phpstr_free(qstr);
        }
 
        /* cookiestore */
        if (zoption = http_curl_getopt(options, "cookiestore", IS_STRING)) {
-               HTTP_CURL_OPT(COOKIEFILE, http_curl_copystr(Z_STRVAL_P(zoption)));
-               HTTP_CURL_OPT(COOKIEJAR, http_curl_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(COOKIEFILE, http_request_copystr(Z_STRVAL_P(zoption)));
+               HTTP_CURL_OPT(COOKIEJAR, http_request_copystr(Z_STRVAL_P(zoption)));
        }
 
        /* resume */
@@ -488,8 +512,7 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
                                curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, http_request_method_name(meth));
                        } else {
                                http_error_ex(E_WARNING, HTTP_E_CURL, "Unsupported request method: %d", meth);
-                               status = FAILURE;
-                               goto http_request_end;
+                               return FAILURE;
                        }
                break;
        }
@@ -515,86 +538,95 @@ PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const c
 
                        default:
                                http_error_ex(E_WARNING, HTTP_E_CURL, "Unknown request body type: %d", body->type);
-                               status = FAILURE;
-                               goto http_request_end;
+                               return FAILURE;
                        break;
                }
        }
 
+       return SUCCESS;
+}
+/* }}} */
+
+/* {{{ STATUS http_request_exec(CURL *, HashTable *) */
+PHP_HTTP_API STATUS _http_request_exec(CURL *ch, HashTable *info TSRMLS_DC)
+{
+       CURLcode result;
+       
        /* perform request */
-       if (CURLE_OK == (result = curl_easy_perform(ch))) {
+       if (CURLE_OK != (result = curl_easy_perform(ch))) {
+               http_error_ex(E_WARNING, HTTP_E_CURL, "Could not perform request: %s", curl_easy_strerror(result));
+               return FAILURE;
+       } else {
                /* get curl info */
                if (info) {
-                       zval array;
-                       Z_ARRVAL(array) = info;
+                       http_request_info(ch, info);
+               }
+               return SUCCESS;
+       }
+}
+/* }}} */
+
+/* {{{ void http_request_info(CURL *, HashTable *) */
+PHP_HTTP_API void _http_request_info(CURL *ch, HashTable *info TSRMLS_DC)
+{
+       zval array;
+       Z_ARRVAL(array) = info;
 
-                       HTTP_CURL_INFO(EFFECTIVE_URL);
+       HTTP_CURL_INFO(EFFECTIVE_URL);
 #if LIBCURL_VERSION_NUM >= 0x070a07
-                       HTTP_CURL_INFO(RESPONSE_CODE);
+       HTTP_CURL_INFO(RESPONSE_CODE);
 #else
-                       HTTP_CURL_INFO_EX(HTTP_CODE, RESPONSE_CODE);
+       HTTP_CURL_INFO_EX(HTTP_CODE, RESPONSE_CODE);
 #endif
-                       HTTP_CURL_INFO(HTTP_CONNECTCODE);
+       HTTP_CURL_INFO(HTTP_CONNECTCODE);
 #if LIBCURL_VERSION_NUM >= 0x070500
-                       HTTP_CURL_INFO(FILETIME);
+       HTTP_CURL_INFO(FILETIME);
 #endif
-                       HTTP_CURL_INFO(TOTAL_TIME);
-                       HTTP_CURL_INFO(NAMELOOKUP_TIME);
-                       HTTP_CURL_INFO(CONNECT_TIME);
-                       HTTP_CURL_INFO(PRETRANSFER_TIME);
-                       HTTP_CURL_INFO(STARTTRANSFER_TIME);
+       HTTP_CURL_INFO(TOTAL_TIME);
+       HTTP_CURL_INFO(NAMELOOKUP_TIME);
+       HTTP_CURL_INFO(CONNECT_TIME);
+       HTTP_CURL_INFO(PRETRANSFER_TIME);
+       HTTP_CURL_INFO(STARTTRANSFER_TIME);
 #if LIBCURL_VERSION_NUM >= 0x070907
-                       HTTP_CURL_INFO(REDIRECT_TIME);
-                       HTTP_CURL_INFO(REDIRECT_COUNT);
+       HTTP_CURL_INFO(REDIRECT_TIME);
+       HTTP_CURL_INFO(REDIRECT_COUNT);
 #endif
-                       HTTP_CURL_INFO(SIZE_UPLOAD);
-                       HTTP_CURL_INFO(SIZE_DOWNLOAD);
-                       HTTP_CURL_INFO(SPEED_DOWNLOAD);
-                       HTTP_CURL_INFO(SPEED_UPLOAD);
-                       HTTP_CURL_INFO(HEADER_SIZE);
-                       HTTP_CURL_INFO(REQUEST_SIZE);
-                       HTTP_CURL_INFO(SSL_VERIFYRESULT);
+       HTTP_CURL_INFO(SIZE_UPLOAD);
+       HTTP_CURL_INFO(SIZE_DOWNLOAD);
+       HTTP_CURL_INFO(SPEED_DOWNLOAD);
+       HTTP_CURL_INFO(SPEED_UPLOAD);
+       HTTP_CURL_INFO(HEADER_SIZE);
+       HTTP_CURL_INFO(REQUEST_SIZE);
+       HTTP_CURL_INFO(SSL_VERIFYRESULT);
 #if LIBCURL_VERSION_NUM >= 0x070c03
-                       /*HTTP_CURL_INFO(SSL_ENGINES); todo: CURLINFO_SLIST */
+       /*HTTP_CURL_INFO(SSL_ENGINES); todo: CURLINFO_SLIST */
 #endif
-                       HTTP_CURL_INFO(CONTENT_LENGTH_DOWNLOAD);
-                       HTTP_CURL_INFO(CONTENT_LENGTH_UPLOAD);
-                       HTTP_CURL_INFO(CONTENT_TYPE);
+       HTTP_CURL_INFO(CONTENT_LENGTH_DOWNLOAD);
+       HTTP_CURL_INFO(CONTENT_LENGTH_UPLOAD);
+       HTTP_CURL_INFO(CONTENT_TYPE);
 #if LIBCURL_VERSION_NUM >= 0x070a03
-                       /*HTTP_CURL_INFO(PRIVATE);*/
+       /*HTTP_CURL_INFO(PRIVATE);*/
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070a08
-                       HTTP_CURL_INFO(HTTPAUTH_AVAIL);
-                       HTTP_CURL_INFO(PROXYAUTH_AVAIL);
+       HTTP_CURL_INFO(HTTPAUTH_AVAIL);
+       HTTP_CURL_INFO(PROXYAUTH_AVAIL);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070c02
-                       /*HTTP_CURL_INFO(OS_ERRNO);*/
+       /*HTTP_CURL_INFO(OS_ERRNO);*/
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070c03
-                       HTTP_CURL_INFO(NUM_CONNECTS);
+       HTTP_CURL_INFO(NUM_CONNECTS);
 #endif
-               }
-       } else {
-               http_error_ex(E_WARNING, HTTP_E_CURL, "Could not perform request: %s", curl_easy_strerror(result));
-               status = FAILURE;
-       }
-
-http_request_end:
-       /* free strings copied with http_curl_copystr() */
-       zend_llist_clean(&HTTP_G(request).curl.copies);
-
-       /* clean curl handle if acquired */
-       if (clean_curl) {
-               curl_easy_cleanup(ch);
-               ch = NULL;
-       }
+}
+/* }}} */
 
-       /* finalize response */
-       if (response) {
-               phpstr_fix(PHPSTR(response));
+/* {{{ STATUS http_request_ex(CURL *, http_request_method, char *, http_request_body, HashTable, HashTable, phpstr *) */
+PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const char *url, http_request_body *body, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC)
+{
+       if (SUCCESS != http_request_init(ch, meth, url, body, options, response)) {
+               return FAILURE;
        }
-
-       return status;
+       return http_request_exec(ch, info);
 }
 /* }}} */
 
@@ -687,6 +719,143 @@ PHP_HTTP_API STATUS _http_request_method_unregister(unsigned long method TSRMLS_
 }
 /* }}} */
 
+
+/* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */
+PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC)
+{
+       zend_bool free_pool;
+
+       if ((free_pool = (!pool))) {
+               pool = emalloc(sizeof(http_request_pool));
+               pool->ch = NULL;
+       }
+
+       if (!pool->ch) {
+               if (!(pool->ch = curl_multi_init())) {
+                       http_error(E_WARNING, HTTP_E_CURL, "Could not initialize curl");
+                       if (free_pool) {
+                               efree(pool);
+                       }
+                       return NULL;
+               }
+       }
+
+       pool->unfinished = 0;
+       zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
+       zend_llist_init(&pool->bodies, sizeof(http_request_body *), (llist_dtor_func_t) http_request_pool_freebody, 0);
+
+       return pool;
+}
+/* }}} */
+
+/* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */
+PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request TSRMLS_DC)
+{
+       getObjectEx(http_request_object, req, request);
+
+       if (req->attached) {
+               http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is already member of an HttpRequestPool");
+       } else {
+               CURLMcode code;
+               http_request_body *body = http_request_body_new();
+               zval *info = GET_PROP_EX(req, request, responseInfo);
+
+               if (SUCCESS != http_request_object_requesthandler(req, request, body)) {
+                       efree(body);
+                       http_error_ex(E_WARNING, HTTP_E_CURL, "Could not initialize HttpRequest object for attaching to the HttpRequestPool");
+               } else if (CURLM_OK != (code = curl_multi_add_handle(pool->ch, req->ch))) {
+                       http_error_ex(E_WARNING, HTTP_E_CURL, "Could not attach HttpRequest object to the HttpRequestPool: %s", curl_multi_strerror(code));
+               } else {
+                       req->attached = 1;
+                       zval_add_ref(&request);
+                       zend_llist_add_element(&pool->handles, &request);
+                       zend_llist_add_element(&pool->bodies, &body);
+                       return SUCCESS;
+               }
+       }
+       return FAILURE;
+}
+/* }}} */
+
+/* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */
+PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request TSRMLS_DC)
+{
+       getObjectEx(http_request_object, req, request);
+
+       if (!req->attached) {
+               http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is not attached to an HttpRequestPool");
+       } else {
+               CURLMcode code;
+
+               if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->ch))) {
+                       http_error_ex(E_WARNING, HTTP_E_CURL, "Could not detach HttpRequest object from the HttpRequestPool: %s", curl_multi_strerror(code));
+               } else {
+                       req->attached = 0;
+                       zval_ptr_dtor(&request);
+                       return SUCCESS;
+               }
+       }
+       return FAILURE;
+}
+/* }}} */
+
+/* {{{ STATUS http_request_pool_send(http_request_pool *) */
+PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool TSRMLS_DC)
+{
+       http_request_pool_perform(pool);
+       while (pool->unfinished) {
+               if (SUCCESS != http_request_pool_select(pool)) {
+                       http_error(E_WARNING, HTTP_E_CURL, "Socket error");
+                       return FAILURE;
+               }
+               http_request_pool_perform(pool);
+       }
+       zend_llist_apply(&pool->handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
+       return SUCCESS;
+}
+/* }}} */
+
+/*#*/
+
+/* {{{ static void http_request_pool_free_body(http_request_body *) */
+static void http_request_pool_freebody(http_request_body **body)
+{
+       TSRMLS_FETCH();
+       http_request_body_free(*body);
+}
+/* }}} */
+
+/* {{{ static void http_request_pool_responsehandler(zval **) */
+static void http_request_pool_responsehandler(zval **req TSRMLS_DC)
+{
+       getObjectEx(http_request_object, obj, *req);
+       http_request_object_responsehandler(obj, *req, NULL);
+}
+/* }}} */
+
+/* {{{ static inline STATUS http_request_pool_select(http_request_pool *) */
+static inline STATUS http_request_pool_select(http_request_pool *pool)
+{
+       int MAX;
+       fd_set R, W, E;
+       struct timeval timeout = {1, 0};
+
+       FD_ZERO(&R);
+       FD_ZERO(&W);
+       FD_ZERO(&E);
+
+       curl_multi_fdset(pool->ch, &R, &W, &E, &MAX);
+       return (-1 != select(MAX + 1, &R, &W, &E, &timeout)) ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+/* {{{ static inline void http_request_pool_perform(http_request_pool *) */
+static inline void http_request_pool_perform(http_request_pool *pool)
+{
+       while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
+}
+/* }}} */
+
 /* {{{ char *http_request_methods[] */
 static const char *const http_request_methods[] = {
        "UNKOWN",
@@ -725,15 +894,6 @@ static const char *const http_request_methods[] = {
 };
 /* }}} */
 
-/* {{{ static inline char *http_curl_copystr(char *) */
-static inline char *_http_curl_copystr(const char *str TSRMLS_DC)
-{
-       char *new_str = estrdup(str);
-       zend_llist_add_element(&HTTP_G(request).curl.copies, &new_str);
-       return new_str;
-}
-/* }}} */
-
 /* {{{ static size_t http_curl_write_callback(char *, size_t, size_t, void *) */
 static size_t http_curl_write_callback(char *buf, size_t len, size_t n, void *s)
 {
index d9dd8f2..f43d3ad 100644 (file)
 #include "php_http_std_defs.h"
 #include "php_http_request_object.h"
 #include "php_http_request_api.h"
+#include "php_http_api.h"
+#include "php_http_url_api.h"
+#include "php_http_message_api.h"
+#include "php_http_message_object.h"
 
 #ifdef ZEND_ENGINE_2
 #ifdef HTTP_HAVE_CURL
@@ -85,7 +89,7 @@ zend_function_entry http_request_object_fe[] = {
        PHP_ME(HttpRequest, setPutFile, NULL, ZEND_ACC_PUBLIC)
        PHP_ME(HttpRequest, getPutFile, NULL, ZEND_ACC_PUBLIC)
        PHP_ME(HttpRequest, unsetPutFile, NULL, ZEND_ACC_PUBLIC)
-       
+
        PHP_ME(HttpRequest, send, NULL, ZEND_ACC_PUBLIC)
 
        PHP_ME(HttpRequest, getResponseData, NULL, ZEND_ACC_PUBLIC)
@@ -152,6 +156,7 @@ zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
        o = ecalloc(1, sizeof(http_request_object));
        o->zo.ce = ce;
        o->ch = curl_easy_init();
+       o->attached = 0;
 
        phpstr_init_ex(&o->response, HTTP_CURLBUF_SIZE, 0);
 
@@ -200,6 +205,131 @@ void _http_request_object_free(zend_object *object TSRMLS_DC)
        efree(o);
 }
 
+STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr, http_request_body *body TSRMLS_DC)
+{
+       zval *meth, *URL, *qdata, *opts;
+       char *request_uri, *uri;
+       STATUS status;
+
+       if (!body) {
+               return FAILURE;
+       }
+       if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
+               http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl");
+               return FAILURE;
+       }
+
+       meth  = GET_PROP(obj, method);
+       URL   = GET_PROP(obj, url);
+       qdata = GET_PROP(obj, queryData);
+       opts  = GET_PROP(obj, options);
+
+       // HTTP_URI_MAXLEN+1 long char *
+       if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) {
+               return FAILURE;
+       }
+
+       if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
+               if (!strchr(request_uri, '?')) {
+                       strcat(request_uri, "?");
+               } else {
+                       strcat(request_uri, "&");
+               }
+               strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
+       }
+       
+       uri = http_request_copystr(request_uri);
+       efree(request_uri);
+
+       switch (Z_LVAL_P(meth))
+       {
+               case HTTP_GET:
+               case HTTP_HEAD:
+                       body->type = -1;
+                       status = http_request_init(obj->ch, Z_LVAL_P(meth), uri, NULL, Z_ARRVAL_P(opts), &obj->response);
+               break;
+
+               case HTTP_PUT:
+               {
+                       php_stream *stream;
+                       php_stream_statbuf ssb;
+                       zval *file = GET_PROP(obj, putFile);
+
+                       if (    (stream = php_stream_open_wrapper(Z_STRVAL_P(file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) &&
+                                       !php_stream_stat(stream, &ssb)) {
+                               body->type = HTTP_REQUEST_BODY_UPLOADFILE;
+                               body->data = stream;
+                               body->size = ssb.sb.st_size;
+
+                               status = http_request_init(obj->ch, HTTP_PUT, uri, body, Z_ARRVAL_P(opts), &obj->response);
+                       } else {
+                               status = FAILURE;
+                       }
+               }
+               break;
+
+               case HTTP_POST:
+               {
+                       zval *fields = GET_PROP(obj, postFields), *files = GET_PROP(obj, postFiles);
+
+                       if (SUCCESS == (status = http_request_body_fill(body, Z_ARRVAL_P(fields), Z_ARRVAL_P(files)))) {
+                               status = http_request_init(obj->ch, HTTP_POST, uri, body, Z_ARRVAL_P(opts), &obj->response);
+                       }
+               }
+               break;
+
+               default:
+               {
+                       zval *post = GET_PROP(obj, postData);
+
+                       body->type = HTTP_REQUEST_BODY_CSTRING;
+                       body->data = Z_STRVAL_P(post);
+                       body->size = Z_STRLEN_P(post);
+
+                       status = http_request_init(obj->ch, Z_LVAL_P(meth), uri, body, Z_ARRVAL_P(opts), &obj->response);
+               }
+               break;
+       }
+
+       return status;
+}
+
+STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr, HashTable *info TSRMLS_DC)
+{
+       http_message *msg;
+       
+       phpstr_fix(&obj->response);
+
+       if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
+               char *body;
+               size_t body_len;
+               zval *headers, *message = GET_PROP(obj, responseMessage), *resp = GET_PROP(obj, responseData);
+
+               UPD_PROP(obj, long, responseCode, msg->info.response.code);
+
+               MAKE_STD_ZVAL(headers)
+               array_init(headers);
+
+               zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+               phpstr_data(PHPSTR(msg), &body, &body_len);
+
+               add_assoc_zval(resp, "headers", headers);
+               add_assoc_stringl(resp, "body", body, body_len, 0);
+
+               //zval_dtor(&message);
+               Z_TYPE_P(message)  = IS_OBJECT;
+               message->value.obj = http_message_object_from_msg(msg);
+               SET_PROP(obj, responseMessage, message);
+
+               if (info) {
+                       http_request_info(obj->ch, info);
+               }
+
+               return SUCCESS;
+       }
+       return FAILURE;
+}
+
 #endif /* HTTP_HAVE_CURL */
 #endif /* ZEND_ENGINE_2 */
 
diff --git a/http_requestpool_object.c b/http_requestpool_object.c
new file mode 100644 (file)
index 0000000..09fc261
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+   +----------------------------------------------------------------------+
+   | PECL :: http                                                         |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license, that  |
+   | is bundled with this package in the file LICENSE, and is available   |
+   | through the world-wide-web at http://www.php.net/license/3_0.txt.    |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2004-2005 Michael Wallner <mike@php.net>               |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+
+#ifdef HAVE_CONFIG_H
+#      include "config.h"
+#endif
+
+#ifdef HTTP_HAVE_CURL
+#      ifdef PHP_WIN32
+#              include <winsock2.h>
+#      endif
+#      include <curl/curl.h>
+#endif
+
+#include "php.h"
+
+#include "php_http_std_defs.h"
+#include "php_http_requestpool_object.h"
+#include "php_http_request_api.h"
+
+#ifdef ZEND_ENGINE_2
+#ifdef HTTP_HAVE_CURL
+
+#define http_requestpool_object_declare_default_properties() _http_requestpool_object_declare_default_properties(TSRMLS_C)
+static inline void _http_requestpool_object_declare_default_properties(TSRMLS_D);
+
+zend_class_entry *http_requestpool_object_ce;
+zend_function_entry http_requestpool_object_fe[] = {
+       PHP_ME(HttpRequestPool, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpRequestPool, attach, NULL, ZEND_ACC_PUBLIC)
+       PHP_ME(HttpRequestPool, detach, NULL, ZEND_ACC_PUBLIC)
+       PHP_ME(HttpRequestPool, send, NULL, ZEND_ACC_PUBLIC)
+
+       {NULL, NULL, NULL}
+};
+static zend_object_handlers http_requestpool_object_handlers;
+
+void _http_requestpool_object_init(INIT_FUNC_ARGS)
+{
+       HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
+}
+
+zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+       zend_object_value ov;
+       http_requestpool_object *o;
+
+       o = ecalloc(1, sizeof(http_requestpool_object));
+       o->zo.ce = ce;
+
+       http_request_pool_init(&o->pool);
+
+       ALLOC_HASHTABLE(OBJ_PROP(o));
+       zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+
+       ov.handle = zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, http_requestpool_object_free, NULL TSRMLS_CC);
+       ov.handlers = &http_requestpool_object_handlers;
+
+       return ov;
+}
+
+static inline void _http_requestpool_object_declare_default_properties(TSRMLS_D)
+{
+       zend_class_entry *ce = http_requestpool_object_ce;
+
+       DCL_PROP_N(PROTECTED, pool);
+}
+
+void _http_requestpool_object_free(zend_object *object TSRMLS_DC)
+{
+       http_requestpool_object *o = (http_requestpool_object *) object;
+
+       if (OBJ_PROP(o)) {
+               zend_hash_destroy(OBJ_PROP(o));
+               FREE_HASHTABLE(OBJ_PROP(o));
+       }
+       if (o->pool.ch) {
+               curl_multi_cleanup(o->pool.ch);
+       }
+       efree(o);
+}
+
+#endif /* HTTP_HAVE_CURL */
+#endif /* ZEND_ENGINE_2 */
+
+/*
+ * 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
+ */
+
index bee4e70..25b2232 100644 (file)
@@ -66,16 +66,26 @@ typedef enum {
 #define HTTP_STD_REQUEST_METHOD(m) ((m > HTTP_NO_REQUEST_METHOD) && (m < HTTP_MAX_REQUEST_METHOD))
 #define HTTP_CUSTOM_REQUEST_METHOD(m) (m - HTTP_MAX_REQUEST_METHOD)
 
-#define HTTP_REQUEST_BODY_CSTRING              0
-#define HTTP_REQUEST_BODY_CURLPOST             1
-#define HTTP_REQUEST_BODY_UPLOADFILE   2
-#define HTTP_REQUEST_BODY_UPLOADDATA   3
+#define HTTP_REQUEST_BODY_CSTRING              1
+#define HTTP_REQUEST_BODY_CURLPOST             2
+#define HTTP_REQUEST_BODY_UPLOADFILE   3
+#define HTTP_REQUEST_BODY_UPLOADDATA   4
 typedef struct {
        int type;
        void *data;
        size_t size;
 } http_request_body;
 
+typedef struct {
+       CURLM *ch;
+       zend_llist handles;
+       zend_llist bodies;
+       int unfinished;
+} http_request_pool;
+
+#define http_request_copystr(s) _http_request_copystr((s) TSRMLS_CC)
+PHP_HTTP_API char *_http_request_copystr(const char *string TSRMLS_DC);
+
 #define http_request_method_name(m) _http_request_method_name((m) TSRMLS_CC)
 PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC);
 
@@ -88,12 +98,39 @@ PHP_HTTP_API unsigned long _http_request_method_register(const char *method TSRM
 #define http_request_method_unregister(mn) _http_request_method_unregister((mn) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_request_method_unregister(unsigned long method TSRMLS_DC);
 
+#define http_request_body_new() _http_request_body_new(TSRMLS_C)
+PHP_HTTP_API http_request_body *_http_request_body_new(TSRMLS_D);
+
 #define http_request_body_fill(b, fields, files) _http_request_body_fill((b), (fields), (files) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files TSRMLS_DC);
 
 #define http_request_body_dtor(b) _http_request_body_dtor((b) TSRMLS_CC)
 PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC);
 
+#define http_request_body_free(b) _http_request_body_free((b) TSRMLS_CC)
+PHP_HTTP_API void _http_request_body_free(http_request_body *body TSRMLS_DC);
+
+#define http_request_pool_init(p) _http_request_pool_init((p) TSRMLS_CC)
+PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC);
+
+#define http_request_pool_attach(p, r) _http_request_pool_attach((p), (r) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request TSRMLS_DC);
+
+#define http_request_pool_detach(p, r) _http_request_pool_detach((p), (r) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request TSRMLS_DC);
+
+#define http_request_pool_send(p) _http_request_pool_send((p) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool TSRMLS_DC);
+
+#define http_request_init(ch, meth, url, body, options, response) _http_request_init((ch), (meth), (url), (body), (options), (response) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_request_init(CURL *ch, http_request_method meth, const char *url, http_request_body *body, HashTable *options, phpstr *response TSRMLS_DC);
+
+#define http_request_exec(ch, i) _http_request_exec((ch), (i) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_request_exec(CURL *ch, HashTable *info TSRMLS_DC);
+
+#define http_request_info(ch, i) _http_request_info((ch), (i) TSRMLS_CC)
+PHP_HTTP_API void _http_request_info(CURL *ch, HashTable *info TSRMLS_DC);
+
 #define http_request(meth, url, body, opt, info, resp) _http_request_ex(NULL, (meth), (url), (body), (opt), (info), (resp) TSRMLS_CC)
 #define http_request_ex(ch, meth, url, body, opt, info, resp) _http_request_ex((ch), (meth), (url), (body), (opt), (info), (resp) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_request_ex(CURL *ch, http_request_method meth, const char *URL, http_request_body *body, HashTable *options, HashTable *info, phpstr *response TSRMLS_DC);
index 57051b7..e8326b3 100644 (file)
 
 #include <curl/curl.h>
 
+#include "php_http_request_api.h"
 #include "phpstr/phpstr.h"
 
 typedef struct {
        zend_object zo;
        CURL *ch;
+       zend_bool attached;
        phpstr response;
 } http_request_object;
 
@@ -44,6 +46,11 @@ extern zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC
 #define http_request_object_free _http_request_object_free
 extern void _http_request_object_free(zend_object *object TSRMLS_DC);
 
+#define http_request_object_requesthandler(req, this, body) _http_request_object_requesthandler((req), (this), (body) TSRMLS_CC)
+extern STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr, http_request_body *body TSRMLS_DC);
+#define http_request_object_responsehandler(req, this, info) _http_request_object_responsehandler((req), (this), (info) TSRMLS_CC)
+extern STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr, HashTable *info TSRMLS_DC);
+
 PHP_METHOD(HttpRequest, __construct);
 PHP_METHOD(HttpRequest, __destruct);
 PHP_METHOD(HttpRequest, setOptions);
diff --git a/php_http_requestpool_object.h b/php_http_requestpool_object.h
new file mode 100644 (file)
index 0000000..1981c85
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+   +----------------------------------------------------------------------+
+   | PECL :: http                                                         |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license, that  |
+   | is bundled with this package in the file LICENSE, and is available   |
+   | through the world-wide-web at http://www.php.net/license/3_0.txt.    |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2004-2005 Michael Wallner <mike@php.net>               |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_HTTP_REQUESTPOOL_OBJECT_H
+#define PHP_HTTP_REQUESTPOOL_OBJECT_H
+#ifdef HTTP_HAVE_CURL
+#ifdef ZEND_ENGINE_2
+
+#ifdef PHP_WIN32
+#      include <winsock2.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "php_http_request_api.h"
+
+typedef struct {
+       zend_object zo;
+       http_request_pool pool;
+} http_requestpool_object;
+
+extern zend_class_entry *http_requestpool_object_ce;
+extern zend_function_entry http_requestpool_object_fe[];
+
+#define http_requestpool_object_init() _http_requestpool_object_init(INIT_FUNC_ARGS_PASSTHRU)
+extern void _http_requestpool_object_init(INIT_FUNC_ARGS);
+#define http_requestpool_object_new _http_requestpool_object_new
+extern zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC);
+#define http_requestpool_object_free _http_requestpool_object_free
+extern void _http_requestpool_object_free(zend_object *object TSRMLS_DC);
+
+PHP_METHOD(HttpRequestPool, __construct);
+PHP_METHOD(HttpRequestPool, attach);
+PHP_METHOD(HttpRequestPool, detach);
+PHP_METHOD(HttpRequestPool, send);
+
+#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
+ */
+
index 42b67ed..0e0bc14 100644 (file)
@@ -199,9 +199,12 @@ typedef int STATUS;
 #      define DCL_PROP(a, t, n, v) zend_declare_property_ ##t(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
 #      define DCL_PROP_Z(a, n, v) zend_declare_property(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
 #      define DCL_PROP_N(a, n) zend_declare_property_null(ce, (#n), sizeof(#n), (ZEND_ACC_ ##a) TSRMLS_CC)
-#      define UPD_PROP(o, t, n, v) zend_update_property_ ##t(o->zo.ce, getThis(), (#n), sizeof(#n), (v) TSRMLS_CC)
-#      define SET_PROP(o, n, z) zend_update_property(o->zo.ce, getThis(), (#n), sizeof(#n), (z) TSRMLS_CC)
-#      define GET_PROP(o, n) zend_read_property(o->zo.ce, getThis(), (#n), sizeof(#n), 0 TSRMLS_CC)
+#      define UPD_PROP(o, t, n, v) UPD_PROP_EX(o, getThis(), t, n, v)
+#      define UPD_PROP_EX(o, this, t, n, v) zend_update_property_ ##t(o->zo.ce, this, (#n), sizeof(#n), (v) TSRMLS_CC)
+#      define SET_PROP(o, n, z) SET_PROP_EX(o, getThis(), n, z)
+#      define SET_PROP_EX(o, this, n, z) zend_update_property(o->zo.ce, this, (#n), sizeof(#n), (z) TSRMLS_CC)
+#      define GET_PROP(o, n) GET_PROP_EX(o, getThis(), n)
+#      define GET_PROP_EX(o, this, n) zend_read_property(o->zo.ce, this, (#n), sizeof(#n), 0 TSRMLS_CC)
 
 #      define INIT_PARR(o, n) \
        { \