summaryrefslogtreecommitdiff
path: root/ext/curl/multi.c
diff options
context:
space:
mode:
authorMáté Kocsis <kocsismate@woohoolabs.com>2020-06-17 16:05:55 +0200
committerMáté Kocsis <kocsismate@woohoolabs.com>2020-06-17 16:11:57 +0200
commitb516566b84c210ce6ceddeb238e45d4b1bcb32ce (patch)
tree353ab0f357eee9583aadf196688c382059568871 /ext/curl/multi.c
parent1e095e3412f0d8be5b245326b72e7ab82c553985 (diff)
downloadphp-git-b516566b84c210ce6ceddeb238e45d4b1bcb32ce.tar.gz
Convert CURL resources to objects
Closes GH-5402 Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>
Diffstat (limited to 'ext/curl/multi.c')
-rw-r--r--ext/curl/multi.c300
1 files changed, 157 insertions, 143 deletions
diff --git a/ext/curl/multi.c b/ext/curl/multi.c
index d8c1caac3c..6a4c48ee18 100644
--- a/ext/curl/multi.c
+++ b/ext/curl/multi.c
@@ -21,6 +21,7 @@
#endif
#include "php.h"
+#include "Zend/zend_interfaces.h"
#ifdef HAVE_CURL
@@ -47,7 +48,17 @@
#define SAVE_CURLM_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
-/* {{{ proto resource curl_multi_init(void)
+/* CurlMultiHandle class */
+
+static zend_class_entry *curl_multi_ce;
+
+static inline php_curlm *curl_multi_from_obj(zend_object *obj) {
+ return (php_curlm *)((char *)(obj) - XtOffsetOf(php_curlm, std));
+}
+
+#define Z_CURL_MULTI_P(zv) curl_multi_from_obj(Z_OBJ_P(zv))
+
+/* {{{ proto CurlMultiHandle curl_multi_init(void)
Returns a new cURL multi handle */
PHP_FUNCTION(curl_multi_init)
{
@@ -55,17 +66,16 @@ PHP_FUNCTION(curl_multi_init)
ZEND_PARSE_PARAMETERS_NONE();
- mh = ecalloc(1, sizeof(php_curlm));
+ object_init_ex(return_value, curl_multi_ce);
+ mh = Z_CURL_MULTI_P(return_value);
mh->multi = curl_multi_init();
mh->handlers = ecalloc(1, sizeof(php_curlm_handlers));
zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0);
-
- RETURN_RES(zend_register_resource(mh, le_curl_multi_handle));
}
/* }}} */
-/* {{{ proto int curl_multi_add_handle(resource mh, resource ch)
+/* {{{ proto int curl_multi_add_handle(CurlMultiHandle mh, Curl ch)
Add a normal cURL handle to a cURL multi handle */
PHP_FUNCTION(curl_multi_add_handle)
{
@@ -76,23 +86,18 @@ PHP_FUNCTION(curl_multi_add_handle)
CURLMcode error = CURLM_OK;
ZEND_PARSE_PARAMETERS_START(2,2)
- Z_PARAM_RESOURCE(z_mh)
- Z_PARAM_RESOURCE(z_ch)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
+ Z_PARAM_OBJECT_OF_CLASS(z_ch, curl_ce)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
-
- if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
+ ch = Z_CURL_P(z_ch);
_php_curl_verify_handlers(ch, 1);
_php_curl_cleanup_handle(ch);
- GC_ADDREF(Z_RES_P(z_ch));
+ Z_ADDREF_P(z_ch);
zend_llist_add_element(&mh->easyh, z_ch);
error = curl_multi_add_handle(mh->multi, ch->cp);
@@ -105,28 +110,17 @@ PHP_FUNCTION(curl_multi_add_handle)
void _php_curl_multi_cleanup_list(void *data) /* {{{ */
{
zval *z_ch = (zval *)data;
- php_curl *ch;
- if (!z_ch) {
- return;
- }
- if (!Z_RES_P(z_ch)->ptr) {
- return;
- }
- if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
- return;
- }
-
- zend_list_delete(Z_RES_P(z_ch));
+ zval_ptr_dtor(z_ch);
}
/* }}} */
/* Used internally as comparison routine passed to zend_list_del_element */
-static int curl_compare_resources( zval *z1, zval *z2 ) /* {{{ */
+static int curl_compare_objects( zval *z1, zval *z2 ) /* {{{ */
{
return (Z_TYPE_P(z1) == Z_TYPE_P(z2) &&
- Z_TYPE_P(z1) == IS_RESOURCE &&
- Z_RES_P(z1) == Z_RES_P(z2));
+ Z_TYPE_P(z1) == IS_OBJECT &&
+ Z_OBJ_P(z1) == Z_OBJ_P(z2));
}
/* }}} */
@@ -139,10 +133,7 @@ static zval *_php_curl_multi_find_easy_handle(php_curlm *mh, CURL *easy) /* {{{
for(pz_ch_temp = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch_temp;
pz_ch_temp = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
-
- if ((tmp_ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch_temp), le_curl_name, le_curl)) == NULL) {
- return NULL;
- }
+ tmp_ch = Z_CURL_P(pz_ch_temp);
if (tmp_ch->cp == easy) {
return pz_ch_temp;
@@ -153,7 +144,7 @@ static zval *_php_curl_multi_find_easy_handle(php_curlm *mh, CURL *easy) /* {{{
}
/* }}} */
-/* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
+/* {{{ proto int curl_multi_remove_handle(CurlMultiHandle mh, Curl ch)
Remove a multi handle from a set of cURL handles */
PHP_FUNCTION(curl_multi_remove_handle)
{
@@ -164,28 +155,23 @@ PHP_FUNCTION(curl_multi_remove_handle)
CURLMcode error = CURLM_OK;
ZEND_PARSE_PARAMETERS_START(2,2)
- Z_PARAM_RESOURCE(z_mh)
- Z_PARAM_RESOURCE(z_ch)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
+ Z_PARAM_OBJECT_OF_CLASS(z_ch, curl_ce)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
-
- if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
+ ch = Z_CURL_P(z_ch);
error = curl_multi_remove_handle(mh->multi, ch->cp);
SAVE_CURLM_ERROR(mh, error);
RETVAL_LONG((zend_long) error);
- zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_resources);
+ zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_objects);
}
/* }}} */
-/* {{{ proto int curl_multi_select(resource mh[, double timeout])
+/* {{{ proto int curl_multi_select(CurlMultiHandle mh[, double timeout])
Get all the sockets associated with the cURL extension, which can then be "selected" */
PHP_FUNCTION(curl_multi_select)
{
@@ -196,14 +182,12 @@ PHP_FUNCTION(curl_multi_select)
CURLMcode error = CURLM_OK;
ZEND_PARSE_PARAMETERS_START(1,2)
- Z_PARAM_RESOURCE(z_mh)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
Z_PARAM_OPTIONAL
Z_PARAM_DOUBLE(timeout)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
error = curl_multi_wait(mh->multi, NULL, 0, (unsigned long) (timeout * 1000.0), &numfds);
if (CURLM_OK != error) {
@@ -215,7 +199,7 @@ PHP_FUNCTION(curl_multi_select)
}
/* }}} */
-/* {{{ proto int curl_multi_exec(resource mh, int &still_running)
+/* {{{ proto int curl_multi_exec(CurlMultiHandle mh, int &still_running)
Run the sub-connections of the current cURL handle */
PHP_FUNCTION(curl_multi_exec)
{
@@ -226,13 +210,11 @@ PHP_FUNCTION(curl_multi_exec)
CURLMcode error = CURLM_OK;
ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_RESOURCE(z_mh)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
Z_PARAM_ZVAL(z_still_running)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
{
zend_llist_position pos;
@@ -241,10 +223,7 @@ PHP_FUNCTION(curl_multi_exec)
for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
-
- if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl)) == NULL) {
- RETURN_THROWS();
- }
+ ch = Z_CURL_P(pz_ch);
_php_curl_verify_handlers(ch, 1);
}
@@ -259,20 +238,18 @@ PHP_FUNCTION(curl_multi_exec)
}
/* }}} */
-/* {{{ proto string curl_multi_getcontent(resource ch)
+/* {{{ proto string curl_multi_getcontent(CurlHandle ch)
Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
PHP_FUNCTION(curl_multi_getcontent)
{
zval *z_ch;
php_curl *ch;
- ZEND_PARSE_PARAMETERS_START(1,1)
- Z_PARAM_RESOURCE(z_ch)
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_OBJECT_OF_CLASS(z_ch, curl_ce)
ZEND_PARSE_PARAMETERS_END();
- if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
- RETURN_THROWS();
- }
+ ch = Z_CURL_P(z_ch);
if (ch->handlers->write->method == PHP_CURL_RETURN) {
if (!ch->handlers->write->buf.s) {
@@ -286,7 +263,7 @@ PHP_FUNCTION(curl_multi_getcontent)
}
/* }}} */
-/* {{{ proto array curl_multi_info_read(resource mh [, int &msgs_in_queue])
+/* {{{ proto array curl_multi_info_read(CurlMultiHandle mh [, int &msgs_in_queue])
Get information about the current transfers */
PHP_FUNCTION(curl_multi_info_read)
{
@@ -298,14 +275,12 @@ PHP_FUNCTION(curl_multi_info_read)
php_curl *ch;
ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_RESOURCE(z_mh)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(zmsgs_in_queue)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
if (tmp_msg == NULL) {
@@ -322,83 +297,46 @@ PHP_FUNCTION(curl_multi_info_read)
/* find the original easy curl handle */
{
- zval *pz_ch = _php_curl_multi_find_easy_handle(mh, tmp_msg->easy_handle);
+ zval *pz_ch = _php_curl_multi_find_easy_handle(mh, tmp_msg->easy_handle);
if (pz_ch != NULL) {
- /* we are adding a reference to the underlying php_curl
- resource, so we need to add one to the resource's refcount
- in order to ensure it doesn't get destroyed when the
- underlying curl easy handle goes out of scope.
- Normally you would call zval_copy_ctor( pz_ch ), or
- SEPARATE_ZVAL, but those create new zvals, which is already
- being done in add_assoc_resource */
- Z_ADDREF_P(pz_ch);
-
/* we must save result to be able to read error message */
- ch = (php_curl*)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl);
+ ch = Z_CURL_P(pz_ch);
SAVE_CURL_ERROR(ch, tmp_msg->data.result);
- /* add_assoc_resource automatically creates a new zval to
- wrap the "resource" represented by the current pz_ch */
-
+ Z_ADDREF_P(pz_ch);
add_assoc_zval(return_value, "handle", pz_ch);
}
}
}
/* }}} */
-/* {{{ proto void curl_multi_close(resource mh)
+/* {{{ proto void curl_multi_close(CurlMultiHandle mh)
Close a set of cURL handles */
PHP_FUNCTION(curl_multi_close)
{
- zval *z_mh;
php_curlm *mh;
+ zval *z_mh;
+
+ zend_llist_position pos;
+ zval *pz_ch;
ZEND_PARSE_PARAMETERS_START(1,1)
- Z_PARAM_RESOURCE(z_mh)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
-
- zend_list_close(Z_RES_P(z_mh));
-}
-/* }}} */
+ mh = Z_CURL_MULTI_P(z_mh);
-void _php_curl_multi_close(zend_resource *rsrc) /* {{{ */
-{
- php_curlm *mh = (php_curlm *)rsrc->ptr;
- if (mh) {
- zend_llist_position pos;
- php_curl *ch;
- zval *pz_ch;
-
- for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
- pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
- /* ptr is NULL means it already be freed */
- if (Z_RES_P(pz_ch)->ptr) {
- if ((ch = (php_curl *) zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl))) {
- _php_curl_verify_handlers(ch, 0);
- }
- }
- }
-
- curl_multi_cleanup(mh->multi);
- zend_llist_clean(&mh->easyh);
- if (mh->handlers->server_push) {
- zval_ptr_dtor(&mh->handlers->server_push->func_name);
- efree(mh->handlers->server_push);
- }
- if (mh->handlers) {
- efree(mh->handlers);
- }
- efree(mh);
- rsrc->ptr = NULL;
+ for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
+ pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
+ php_curl *ch = Z_CURL_P(pz_ch);
+ _php_curl_verify_handlers(ch, 1);
+ curl_multi_remove_handle(mh->multi, ch->cp);
}
+ zend_llist_clean(&mh->easyh);
}
/* }}} */
-/* {{{ proto int curl_multi_errno(resource mh)
+/* {{{ proto int curl_multi_errno(CurlMultiHandle mh)
Return an integer containing the last multi curl error number */
PHP_FUNCTION(curl_multi_errno)
{
@@ -406,12 +344,10 @@ PHP_FUNCTION(curl_multi_errno)
php_curlm *mh;
ZEND_PARSE_PARAMETERS_START(1,1)
- Z_PARAM_RESOURCE(z_mh)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
RETURN_LONG(mh->err.no);
}
@@ -450,7 +386,6 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea
zval pz_ch;
zval headers;
zval retval;
- zend_resource *res;
char *header;
int error;
zend_fcall_info fci = empty_fcall_info;
@@ -460,18 +395,12 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea
return rval;
}
- parent = (php_curl*)zend_fetch_resource(Z_RES_P(pz_parent_ch), le_curl_name, le_curl);
+ parent = Z_CURL_P(pz_parent_ch);
- ch = alloc_curl_handle();
+ ch = init_curl_handle_into_zval(&pz_ch);
ch->cp = easy;
_php_setup_easy_copy_handlers(ch, parent);
- Z_ADDREF_P(pz_parent_ch);
-
- res = zend_register_resource(ch, le_curl);
- ch->res = res;
- ZVAL_RES(&pz_ch, res);
-
size_t i;
array_init(&headers);
for(i=0; i<num_headers; i++) {
@@ -499,7 +428,6 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea
} else if (!Z_ISUNDEF(retval)) {
if (CURL_PUSH_DENY != zval_get_long(&retval)) {
rval = CURL_PUSH_OK;
- GC_ADDREF(Z_RES(pz_ch));
zend_llist_add_element(&mh->easyh, &pz_ch);
} else {
/* libcurl will free this easy handle, avoid double free */
@@ -570,7 +498,7 @@ static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue,
}
/* }}} */
-/* {{{ proto int curl_multi_setopt(resource mh, int option, mixed value)
+/* {{{ proto int curl_multi_setopt(CurlMultiHandle mh, int option, mixed value)
Set an option for the curl multi handle */
PHP_FUNCTION(curl_multi_setopt)
{
@@ -579,14 +507,12 @@ PHP_FUNCTION(curl_multi_setopt)
php_curlm *mh;
ZEND_PARSE_PARAMETERS_START(3,3)
- Z_PARAM_RESOURCE(z_mh)
+ Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
Z_PARAM_LONG(options)
Z_PARAM_ZVAL(zvalue)
ZEND_PARSE_PARAMETERS_END();
- if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
- RETURN_THROWS();
- }
+ mh = Z_CURL_MULTI_P(z_mh);
if (!_php_curl_multi_setopt(mh, options, zvalue, return_value)) {
RETURN_TRUE;
@@ -596,4 +522,92 @@ PHP_FUNCTION(curl_multi_setopt)
}
/* }}} */
+/* CurlMultiHandle class */
+
+static zend_object_handlers curl_multi_handlers;
+
+static zend_object *curl_multi_create_object(zend_class_entry *class_type) {
+ php_curlm *intern = zend_object_alloc(sizeof(php_curlm), class_type);
+
+ zend_object_std_init(&intern->std, class_type);
+ object_properties_init(&intern->std, class_type);
+ intern->std.handlers = &curl_multi_handlers;
+
+ return &intern->std;
+}
+
+static zend_function *curl_multi_get_constructor(zend_object *object) {
+ zend_throw_error(NULL, "Cannot directly construct CurlMultiHandle, use curl_multi_init() instead");
+ return NULL;
+}
+
+void curl_multi_free_obj(zend_object *object)
+{
+ php_curlm *mh = curl_multi_from_obj(object);
+
+ zend_llist_position pos;
+ php_curl *ch;
+ zval *pz_ch;
+
+ for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
+ pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
+ if (!(OBJ_FLAGS(Z_OBJ_P(pz_ch)) & IS_OBJ_FREE_CALLED)) {
+ ch = Z_CURL_P(pz_ch);
+ _php_curl_verify_handlers(ch, 0);
+ }
+ }
+
+ curl_multi_cleanup(mh->multi);
+ zend_llist_clean(&mh->easyh);
+ if (mh->handlers->server_push) {
+ zval_ptr_dtor(&mh->handlers->server_push->func_name);
+ efree(mh->handlers->server_push);
+ }
+ if (mh->handlers) {
+ efree(mh->handlers);
+ }
+
+ zend_object_std_dtor(&mh->std);
+}
+
+static HashTable *curl_multi_get_gc(zend_object *object, zval **table, int *n)
+{
+ php_curlm *curl_multi = curl_multi_from_obj(object);
+
+ zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
+
+ if (curl_multi->handlers) {
+ if (curl_multi->handlers->server_push) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &curl_multi->handlers->server_push->func_name);
+ }
+ }
+
+ zend_llist_position pos;
+ for (zval *pz_ch = (zval *) zend_llist_get_first_ex(&curl_multi->easyh, &pos); pz_ch;
+ pz_ch = (zval *) zend_llist_get_next_ex(&curl_multi->easyh, &pos)) {
+ zend_get_gc_buffer_add_zval(gc_buffer, pz_ch);
+ }
+
+ zend_get_gc_buffer_use(gc_buffer, table, n);
+
+ return zend_std_get_properties(object);
+}
+
+void curl_multi_register_class(const zend_function_entry *method_entries) {
+ zend_class_entry ce_multi;
+ INIT_CLASS_ENTRY(ce_multi, "CurlMultiHandle", method_entries);
+ curl_multi_ce = zend_register_internal_class(&ce_multi);
+ curl_multi_ce->ce_flags |= ZEND_ACC_FINAL;
+ curl_multi_ce->create_object = curl_multi_create_object;
+ curl_multi_ce->serialize = zend_class_serialize_deny;
+ curl_multi_ce->unserialize = zend_class_unserialize_deny;
+
+ memcpy(&curl_multi_handlers, &std_object_handlers, sizeof(zend_object_handlers));
+ curl_multi_handlers.offset = XtOffsetOf(php_curlm, std);
+ curl_multi_handlers.free_obj = curl_multi_free_obj;
+ curl_multi_handlers.get_gc = curl_multi_get_gc;
+ curl_multi_handlers.get_constructor = curl_multi_get_constructor;
+ curl_multi_handlers.clone_obj = NULL;
+}
+
#endif