From b3fc227f0180cc93c521ef52bee7e4faa71c9a4c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 25 Oct 2005 12:01:30 +0000 Subject: [PATCH] - clone() support for HttpRequest - disallow clone() on HttpRequestPool --- http_message_object.c | 25 ++++++++--------- http_request_object.c | 53 +++++++++++++++++++++++++++++------ http_request_pool_api.c | 4 +++ http_requestpool_object.c | 1 + php_http_message_object.h | 13 ++++----- php_http_request_object.h | 10 ++++--- php_http_requestpool_object.h | 4 +-- php_http_std_defs.h | 16 +++++++++-- tests/cloning_001.phpt | 29 +++++++++++++++++++ 9 files changed, 119 insertions(+), 36 deletions(-) create mode 100644 tests/cloning_001.phpt diff --git a/http_message_object.c b/http_message_object.c index 336d250..50d9491 100644 --- a/http_message_object.c +++ b/http_message_object.c @@ -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(); diff --git a/http_request_object.c b/http_request_object.c index aef84e9..d32f858 100644 --- a/http_request_object.c +++ b/http_request_object.c @@ -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(); } diff --git a/http_request_pool_api.c b/http_request_pool_api.c index 34bc1cb..ca7aec7 100644 --- a/http_request_pool_api.c +++ b/http_request_pool_api.c @@ -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 } /* }}} */ diff --git a/http_requestpool_object.c b/http_requestpool_object.c index cbbd6f0..2281f40 100644 --- a/http_requestpool_object.c +++ b/http_requestpool_object.c @@ -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; } diff --git a/php_http_message_object.h b/php_http_message_object.h index 38eb79b..c6a70f3 100644 --- a/php_http_message_object.h +++ b/php_http_message_object.h @@ -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 diff --git a/php_http_request_object.h b/php_http_request_object.h index 12769f5..7ae1fca 100644 --- a/php_http_request_object.h +++ b/php_http_request_object.h @@ -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); diff --git a/php_http_requestpool_object.h b/php_http_requestpool_object.h index cd5914f..2c70a01 100644 --- a/php_http_requestpool_object.h +++ b/php_http_requestpool_object.h @@ -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); diff --git a/php_http_std_defs.h b/php_http_std_defs.h index 6bde00c..f9485e5 100644 --- a/php_http_std_defs.h +++ b/php_http_std_defs.h @@ -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 index 0000000..73b7734 --- /dev/null +++ b/tests/cloning_001.phpt @@ -0,0 +1,29 @@ +--TEST-- +cloning +--SKIPIF-- + +--FILE-- +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 -- 2.30.2