- clone() support for HttpRequest
authorMichael Wallner <mike@php.net>
Tue, 25 Oct 2005 12:01:30 +0000 (12:01 +0000)
committerMichael Wallner <mike@php.net>
Tue, 25 Oct 2005 12:01:30 +0000 (12:01 +0000)
- disallow clone() on HttpRequestPool

http_message_object.c
http_request_object.c
http_request_pool_api.c
http_requestpool_object.c
php_http_message_object.h
php_http_request_object.h
php_http_requestpool_object.h
php_http_std_defs.h
tests/cloning_001.phpt [new file with mode: 0644]

index 336d2504a8b14ad7c4d01cbca8cd72c06e5122f3..50d949131038d04afc93ae1b85f0f420e70225b8 100644 (file)
@@ -149,21 +149,25 @@ PHP_MINIT_FUNCTION(http_message_object)
 
 zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
 {
-       return http_message_object_new_ex(ce, NULL);
+       return http_message_object_new_ex(ce, NULL, NULL);
 }
 
-zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg TSRMLS_DC)
+zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC)
 {
        zend_object_value ov;
        http_message_object *o;
 
        o = ecalloc(1, sizeof(http_message_object));
        o->zo.ce = ce;
+       
+       if (ptr) {
+               *ptr = o;
+       }
 
        if (msg) {
                o->message = msg;
                if (msg->parent) {
-                       o->parent = http_message_object_from_msg(msg->parent);
+                       o->parent = http_message_object_new_ex(ce, msg->parent, NULL);
                }
        }
 
@@ -176,9 +180,10 @@ zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message
        return ov;
 }
 
-zend_object_value _http_message_object_clone(zval *this_ptr TSRMLS_DC)
+zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC)
 {
-       return http_message_object_clone_obj(this_ptr TSRMLS_CC);
+       getObject(http_message_object, obj);
+       return http_message_object_new_ex(Z_OBJCE_P(this_ptr), http_message_dup(obj->message), NULL);
 }
 
 static inline void _http_message_object_declare_default_properties(TSRMLS_D)
@@ -216,12 +221,6 @@ void _http_message_object_free(zend_object *object TSRMLS_DC)
        efree(o);
 }
 
-static inline zend_object_value _http_message_object_clone_obj(zval *this_ptr TSRMLS_DC)
-{
-       getObject(http_message_object, obj);
-       return http_message_object_from_msg(http_message_dup(obj->message));
-}
-
 static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
 {
        getObjectEx(http_message_object, obj, object);
@@ -506,7 +505,7 @@ PHP_METHOD(HttpMessage, __construct)
        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
                if (obj->message = http_message_parse(message, length)) {
                        if (obj->message->parent) {
-                               obj->parent = http_message_object_from_msg(obj->message->parent);
+                               obj->parent = http_message_object_new_ex(Z_OBJCE_P(getThis()), obj->message->parent, NULL);
                        }
                }
        } else if (!obj->message) {
@@ -539,7 +538,7 @@ PHP_METHOD(HttpMessage, fromString)
        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
                if (msg = http_message_parse(string, length)) {
                        Z_TYPE_P(return_value) = IS_OBJECT;
-                       return_value->value.obj = http_message_object_from_msg(msg);
+                       return_value->value.obj = http_message_object_new_ex(http_message_object_ce, msg, NULL);
                }
        }
        SET_EH_NORMAL();
index aef84e9de495ba9494c44d94806203a3f00618bd..d32f858c3d40583f752503b7e5236ed72231f84e 100644 (file)
@@ -300,18 +300,27 @@ static zend_object_handlers http_request_object_handlers;
 PHP_MINIT_FUNCTION(http_request_object)
 {
        HTTP_REGISTER_CLASS_EX(HttpRequest, http_request_object, NULL, 0);
-       http_request_object_handlers.clone_obj = NULL;
+       http_request_object_handlers.clone_obj = _http_request_object_clone_obj;
        return SUCCESS;
 }
 
 zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
+{
+       return http_request_object_new_ex(ce, curl_easy_init(), NULL);
+}
+
+zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC)
 {
        zend_object_value ov;
        http_request_object *o;
 
        o = ecalloc(1, sizeof(http_request_object));
        o->zo.ce = ce;
-       o->ch = curl_easy_init();
+       o->ch = ch;
+       
+       if (ptr) {
+               *ptr = o;
+       }
 
        phpstr_init(&o->history);
        phpstr_init(&o->request);
@@ -327,6 +336,24 @@ zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
        return ov;
 }
 
+zend_object_value _http_request_object_clone_obj(zval *this_ptr TSRMLS_DC)
+{
+       zend_object *old_zo;
+       zend_object_value new_ov;
+       http_request_object *new_obj;
+       getObject(http_request_object, old_obj);
+       
+       old_zo = zend_objects_get_address(this_ptr TSRMLS_CC);
+       new_ov = http_request_object_new_ex(old_zo->ce, curl_easy_duphandle(old_obj->ch), &new_obj);
+       
+       zend_objects_clone_members(&new_obj->zo, new_ov, old_zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
+       phpstr_append(&new_obj->history, old_obj->history.data, old_obj->history.used);
+       phpstr_append(&new_obj->request, old_obj->request.data, old_obj->request.used);
+       phpstr_append(&new_obj->response, old_obj->response.data, old_obj->response.used);
+       
+       return new_ov;
+}
+
 static inline void _http_request_object_declare_default_properties(TSRMLS_D)
 {
        zend_class_entry *ce = http_request_object_ce;
@@ -544,6 +571,9 @@ STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this
                        *resp = convert_to_type(IS_ARRAY, GET_PROP(obj, responseData)),
                        *info = convert_to_type(IS_ARRAY, GET_PROP(obj, responseInfo));
 
+               SEP_PROP(&resp);
+               SEP_PROP(&info);
+               
                if (zval_is_true(GET_PROP(obj, recordHistory))) {
                        /* we need to act like a zipper, as we'll receive
                         * the requests and the responses in separate chains
@@ -580,9 +610,10 @@ STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this
 
                add_assoc_zval(resp, "headers", headers);
                add_assoc_stringl(resp, "body", body, body_len, 0);
+               SET_PROP(obj, responseData, resp);
 
                MAKE_STD_ZVAL(message);
-               ZVAL_OBJVAL(message, http_message_object_from_msg(msg));
+               ZVAL_OBJVAL(message, http_message_object_new_ex(http_message_object_ce, msg, NULL));
                SET_PROP(obj, responseMessage, message);
                zval_ptr_dtor(&message);
 
@@ -731,9 +762,11 @@ PHP_METHOD(HttpRequest, setOptions)
        }
        
        old_opts = convert_to_type(IS_ARRAY, GET_PROP(obj, options));
-
+       SEP_PROP(&old_opts);
+       
        if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
                zend_hash_clean(Z_ARRVAL_P(old_opts));
+               SET_PROP(obj, options, old_opts);
                RETURN_TRUE;
        }
        
@@ -1202,11 +1235,13 @@ PHP_METHOD(HttpRequest, setPostFields)
        }
 
        post = convert_to_type(IS_ARRAY, GET_PROP(obj, postFields));
-       zend_hash_clean(Z_ARRVAL_P(post));
        
+       SEP_PROP(&post);
+       zend_hash_clean(Z_ARRVAL_P(post));
        if (post_data && zend_hash_num_elements(Z_ARRVAL_P(post_data))) {
                array_copy(post_data, post);
        }
+       SET_PROP(obj, postFields, post);
 
        RETURN_TRUE;
 }
@@ -1385,11 +1420,13 @@ PHP_METHOD(HttpRequest, setPostFiles)
        }
 
        pFiles = convert_to_type(IS_ARRAY, GET_PROP(obj, postFiles));
-       zend_hash_clean(Z_ARRVAL_P(pFiles));
        
+       SEP_PROP(&pFiles);
+       zend_hash_clean(Z_ARRVAL_P(pFiles));
        if (files && zend_hash_num_elements(Z_ARRVAL_P(files))) {
                array_copy(files, pFiles);
        }
+       SET_PROP(obj, postFiles, pFiles);
 
        RETURN_TRUE;
 }
@@ -1777,7 +1814,7 @@ PHP_METHOD(HttpRequest, getRequestMessage)
 
                SET_EH_THROW_HTTP();
                if (msg = http_message_parse(PHPSTR_VAL(&obj->request), PHPSTR_LEN(&obj->request))) {
-                       RETVAL_OBJVAL(http_message_object_from_msg(msg));
+                       RETVAL_OBJVAL(http_message_object_new_ex(http_message_object_ce, msg, NULL));
                }
                SET_EH_NORMAL();
        }
@@ -1809,7 +1846,7 @@ PHP_METHOD(HttpRequest, getHistory)
 
                SET_EH_THROW_HTTP();
                if (msg = http_message_parse(PHPSTR_VAL(&obj->history), PHPSTR_LEN(&obj->history))) {
-                       RETVAL_OBJVAL(http_message_object_from_msg(msg));
+                       RETVAL_OBJVAL(http_message_object_new_ex(http_message_object_ce, msg, NULL));
                }
                SET_EH_NORMAL();
        }
index 34bc1cb2d8f381d56eb9ebfc4980c7fbdc2b5beb..ca7aec756ad41c40f480159896ce28a5157fb0f3 100644 (file)
@@ -251,7 +251,11 @@ PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool)
        FD_ZERO(&E);
 
        curl_multi_fdset(pool->ch, &R, &W, &E, &MAX);
+#ifdef PHP_WIN32
+       return (SOCKET_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) ? SUCCESS : FAILURE;
+#else
        return (-1 != select(MAX + 1, &R, &W, &E, &timeout)) ? SUCCESS : FAILURE;
+#endif
 }
 /* }}} */
 
index cbbd6f0fb9164f3d229e7b24a241e0d27863215e..2281f40e9785d627723523b2ca1ae56dadcdd328 100644 (file)
@@ -101,6 +101,7 @@ PHP_MINIT_FUNCTION(http_requestpool_object)
 {
        HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
        zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 1, zend_ce_iterator);
+       http_requestpool_object_handlers.clone_obj = NULL;
        return SUCCESS;
 }
 
index 38eb79bce0caf7e556691c9fa70f34b11e3a3cf3..c6a70f3beb878e8dd42fd064143a2751774a9028 100644 (file)
@@ -29,14 +29,13 @@ extern zend_function_entry http_message_object_fe[];
 
 extern PHP_MINIT_FUNCTION(http_message_object);
 
-#define http_message_object_new _http_message_object_new
+#define http_message_object_new(ce) _http_message_object_new((ce) TSRMLS_CC)
 extern zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC);
-#define http_message_object_new_ex(ce, msg) _http_message_object_new_ex(ce, msg TSRMLS_CC)
-#define http_message_object_from_msg(msg) _http_message_object_new_ex(http_message_object_ce, msg TSRMLS_CC)
-extern zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg TSRMLS_DC);
-#define http_message_object_clone(zobj) _http_message_object_clone(zobj TSRMLS_CC)
-extern zend_object_value _http_message_object_clone(zval *object TSRMLS_DC);
-#define http_message_object_free _http_message_object_free
+#define http_message_object_new_ex(ce, msg, ptr) _http_message_object_new_ex((ce), (msg), (ptr) TSRMLS_CC)
+extern zend_object_value _http_message_object_new_ex(zend_class_entry *ce, http_message *msg, http_message_object **ptr TSRMLS_DC);
+#define http_message_object_clone(zobj) _http_message_object_clone_obj(zobj TSRMLS_CC)
+extern zend_object_value _http_message_object_clone_obj(zval *object TSRMLS_DC);
+#define http_message_object_free(o) _http_message_object_free((o) TSRMLS_CC)
 extern void _http_message_object_free(zend_object *object TSRMLS_DC);
 
 #define HTTP_MSG_PROPHASH_TYPE                  276192743LU
index 12769f5f43106a5c46c0d84bc489757d9a2f2c97..7ae1fca1b75212ca609d4e99702f8a079c36bcf6 100644 (file)
@@ -41,12 +41,14 @@ extern zend_function_entry http_request_object_fe[];
 
 extern PHP_MINIT_FUNCTION(http_request_object);
 
-#define http_request_object_new _http_request_object_new
+#define http_request_object_new(ce) _http_request_object_new((ce) TSRMLS_CC)
 extern zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC);
-#define http_request_object_free _http_request_object_free
+#define http_request_object_new_ex(ce, ch, ptr) _http_request_object_new_ex((ce), (ch), (ptr) TSRMLS_CC)
+extern zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL *ch, http_request_object **ptr TSRMLS_DC);
+#define http_request_object_clone(zv) _http_request_object_clone_obj((zv) TSRMLS_CC)
+extern zend_object_value _http_request_object_clone_obj(zval *zobject TSRMLS_DC);
+#define http_request_object_free(o) _http_request_object_free((o) TSRMLS_CC)
 extern void _http_request_object_free(zend_object *object TSRMLS_DC);
-#define http_request_object_clone(o) _http_request_object_clone((o) TSRMLS_CC)
-extern zend_object_value _http_request_object_clone(zval *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);
index cd5914f85a3061b9caa73e1bd8f65733385cff61..2c70a0102229bd6ed05c75ba5bf254a375a01b33 100644 (file)
@@ -38,9 +38,9 @@ extern zend_function_entry http_requestpool_object_fe[];
 
 extern PHP_MINIT_FUNCTION(http_requestpool_object);
 
-#define http_requestpool_object_new _http_requestpool_object_new
+#define http_requestpool_object_new(ce) _http_requestpool_object_new(ce TSRMLS_CC)
 extern zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC);
-#define http_requestpool_object_free _http_requestpool_object_free
+#define http_requestpool_object_free(o) _http_requestpool_object_free(o TSRMLS_CC)
 extern void _http_requestpool_object_free(zend_object *object TSRMLS_DC);
 
 PHP_METHOD(HttpRequestPool, __construct);
index 6bde00ce11952f647dd2fe2bae6440c45a39b422..f9485e57013a935c7f7345a53894d9a26277a773 100644 (file)
@@ -192,7 +192,7 @@ typedef int STATUS;
        { \
                zend_class_entry ce; \
                INIT_CLASS_ENTRY(ce, #classname, name## _fe); \
-               ce.create_object = name## _new; \
+               ce.create_object = _ ##name## _new; \
                name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
                name## _ce->ce_flags |= flags;  \
                memcpy(& name## _handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
@@ -219,7 +219,7 @@ typedef int STATUS;
 
 #      define getObject(t, o) getObjectEx(t, o, getThis())
 #      define getObjectEx(t, o, v) t * o = ((t *) zend_object_store_get_object(v TSRMLS_CC))
-#      define putObject(t, o) zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) t## _free, NULL TSRMLS_CC);
+#      define putObject(t, o) zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) _ ##t## _free, NULL TSRMLS_CC);
 #      define OBJ_PROP(o) (o)->zo.properties
 
 #      define DCL_STATIC_PROP(a, t, n, v)              zend_declare_property_ ##t(ce, (#n), sizeof(#n)-1, (v), (ZEND_ACC_ ##a | ZEND_ACC_STATIC) TSRMLS_CC)
@@ -264,6 +264,18 @@ typedef int STATUS;
                } \
        }
 
+/*
+ * the property *MUST* be updated after SEP_PROP()
+ */ 
+#      define SEP_PROP(zpp) \
+       { \
+               zval **op = zpp; \
+               SEPARATE_ZVAL_IF_NOT_REF(zpp); \
+               if (op != zpp) { \
+                       zval_ptr_dtor(op); \
+               } \
+       }
+
 #      define SET_EH_THROW() SET_EH_THROW_EX(zend_exception_get_default())
 #      define SET_EH_THROW_HTTP() SET_EH_THROW_EX(http_exception_get_default())
 #      define SET_EH_THROW_EX(ex) php_set_error_handling(EH_THROW, ex TSRMLS_CC)
diff --git a/tests/cloning_001.phpt b/tests/cloning_001.phpt
new file mode 100644 (file)
index 0000000..73b7734
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+cloning
+--SKIPIF--
+<?php
+include 'skip.inc';
+checkver(5);
+checkcls('HttpRequest');
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+
+$r1 = new HttpRequest;
+$r2 = clone $r1;
+$r1->setOptions(array('redirect' => 3));
+var_dump($r1->getOptions() == $r2->getOptions());
+$r1->setUrl('http://www.google.com/');
+var_dump($r1->getUrl() == $r2->getUrl());
+$r1->send();
+var_dump($r1->getResponseInfo() == $r2->getResponseInfo());
+
+echo "Done\n";
+?>
+--EXPECTF--
+%sTEST
+bool(false)
+bool(false)
+bool(false)
+Done