Skip to content

Commit 7316e84

Browse files
committed
feat: enable persistent CurlShareHandle objects
This commit introduces a new function, curl_share_init_persistent, that creates a php_curlsh struct that can live beyond a single PHP request. Persisting a curl share handle would allow PHP userspace to cache things like DNS lookups, or even entire connections, between multiple PHP requests, thus reducing work for subsequent requests. I created a new function instead of reusing the existing curl_share_init function since it also takes an array of curl_share_setopt options to set when the persistent handle doesn't yet exist. It is noteworthy that calling curl_share_setopt on the persistent handle would affect future requests using the handle; we could consider preventing this. It is also noteworthy that changing the persistent share options would not take effect if the persistent share already existed; changing the persistent share ID would be sufficient to resolve that.
1 parent bb0c325 commit 7316e84

File tree

5 files changed

+99
-9
lines changed

5 files changed

+99
-9
lines changed

ext/curl/curl.stub.php

+3
Original file line numberDiff line numberDiff line change
@@ -3665,6 +3665,9 @@ function curl_share_errno(CurlShareHandle $share_handle): int {}
36653665
/** @refcount 1 */
36663666
function curl_share_init(): CurlShareHandle {}
36673667

3668+
/** @refcount 1 */
3669+
function curl_share_init_persistent(string $persistent_id, array $shares): CurlShareHandle|false {}
3670+
36683671
function curl_share_setopt(CurlShareHandle $share_handle, int $option, mixed $value): bool {}
36693672

36703673
/** @refcount 1 */

ext/curl/curl_arginfo.h

+8-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/curl/curl_private.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,13 @@ typedef struct {
121121
} php_curlm;
122122

123123
typedef struct _php_curlsh {
124-
CURLSH *share;
124+
CURLSH *share;
125+
zend_bool is_persistent;
126+
125127
struct {
126128
int no;
127129
} err;
130+
128131
zend_object std;
129132
} php_curlsh;
130133

@@ -148,7 +151,8 @@ static inline php_curlsh *curl_share_from_obj(zend_object *obj) {
148151
#define Z_CURL_SHARE_P(zv) curl_share_from_obj(Z_OBJ_P(zv))
149152

150153
void curl_multi_register_handlers(void);
151-
void curl_share_register_handlers(void);
154+
void curl_share_register_handlers(int);
155+
void curl_share_free_obj(zend_object *object);
152156
void curlfile_register_class(void);
153157
zend_result curl_cast_object(zend_object *obj, zval *result, int type);
154158

ext/curl/interface.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ PHP_MINIT_FUNCTION(curl)
409409
curl_multi_register_handlers();
410410

411411
curl_share_ce = register_class_CurlShareHandle();
412-
curl_share_register_handlers();
412+
curl_share_register_handlers(module_number);
413413
curlfile_register_class();
414414

415415
return SUCCESS;

ext/curl/share.c

+81-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,69 @@
2828

2929
#define SAVE_CURLSH_ERROR(__handle, __err) (__handle)->err.no = (int) __err;
3030

31+
static int le_pcurlsh;
32+
33+
/* {{{ Initialize a persistent curl share handle */
34+
PHP_FUNCTION(curl_share_init_persistent)
35+
{
36+
php_curlsh *sh;
37+
38+
zend_string *persistent_id = NULL;
39+
zend_string *persistent_key = NULL;
40+
41+
zend_resource *persisted;
42+
43+
zval *arr, *entry;
44+
45+
ZEND_PARSE_PARAMETERS_START(2, 2)
46+
Z_PARAM_STR_EX(persistent_id, 1, 0)
47+
Z_PARAM_ARRAY(arr)
48+
ZEND_PARSE_PARAMETERS_END();
49+
50+
persistent_key = strpprintf(0, "curl_share_init_persistent:id=%s", ZSTR_VAL(persistent_id));
51+
52+
object_init_ex(return_value, curl_share_ce);
53+
54+
sh = Z_CURL_SHARE_P(return_value);
55+
56+
if ((persisted = zend_hash_find_ptr(&EG(persistent_list), persistent_key)) != NULL) {
57+
if (persisted->type == le_pcurlsh) {
58+
sh->share = persisted->ptr;
59+
sh->is_persistent = 1;
60+
61+
goto cleanup;
62+
}
63+
}
64+
65+
sh->share = curl_share_init();
66+
67+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), entry) {
68+
ZVAL_DEREF(entry);
69+
70+
CURLSHcode error = curl_share_setopt(sh->share, CURLSHOPT_SHARE, zval_get_long(entry));
71+
72+
if (error != CURLSHE_OK) {
73+
php_error_docref(NULL, E_WARNING, "could not construct persistent curl share: %s", curl_share_strerror(error));
74+
goto error;
75+
}
76+
} ZEND_HASH_FOREACH_END();
77+
78+
zend_register_persistent_resource(ZSTR_VAL(persistent_key), ZSTR_LEN(persistent_key), sh->share, le_pcurlsh);
79+
80+
sh->is_persistent = 1;
81+
82+
cleanup:
83+
zend_string_release(persistent_key);
84+
return;
85+
86+
error:
87+
zend_string_release(persistent_key);
88+
curl_share_free_obj(Z_OBJ_P(return_value));
89+
90+
RETURN_FALSE;
91+
}
92+
/* }}} */
93+
3194
/* {{{ Initialize a share curl handle */
3295
PHP_FUNCTION(curl_share_init)
3396
{
@@ -42,6 +105,14 @@ PHP_FUNCTION(curl_share_init)
42105
}
43106
/* }}} */
44107

108+
ZEND_RSRC_DTOR_FUNC(php_pcurlsh_dtor)
109+
{
110+
if (res->ptr) {
111+
curl_share_cleanup(res->ptr);
112+
res->ptr = NULL;
113+
}
114+
}
115+
45116
/* {{{ Close a set of cURL handles */
46117
PHP_FUNCTION(curl_share_close)
47118
{
@@ -79,7 +150,7 @@ static bool _php_curl_share_setopt(php_curlsh *sh, zend_long option, zval *zvalu
79150
PHP_FUNCTION(curl_share_setopt)
80151
{
81152
zval *z_sh, *zvalue;
82-
zend_long options;
153+
zend_long options;
83154
php_curlsh *sh;
84155

85156
ZEND_PARSE_PARAMETERS_START(3,3)
@@ -101,8 +172,8 @@ PHP_FUNCTION(curl_share_setopt)
101172
/* {{{ Return an integer containing the last share curl error number */
102173
PHP_FUNCTION(curl_share_errno)
103174
{
104-
zval *z_sh;
105-
php_curlsh *sh;
175+
zval *z_sh;
176+
php_curlsh *sh;
106177

107178
ZEND_PARSE_PARAMETERS_START(1,1)
108179
Z_PARAM_OBJECT_OF_CLASS(z_sh, curl_share_ce)
@@ -154,13 +225,16 @@ void curl_share_free_obj(zend_object *object)
154225
{
155226
php_curlsh *sh = curl_share_from_obj(object);
156227

157-
curl_share_cleanup(sh->share);
228+
if (!sh->is_persistent) {
229+
curl_share_cleanup(sh->share);
230+
}
231+
158232
zend_object_std_dtor(&sh->std);
159233
}
160234

161235
static zend_object_handlers curl_share_handlers;
162236

163-
void curl_share_register_handlers(void) {
237+
void curl_share_register_handlers(int module_number) {
164238
curl_share_ce->create_object = curl_share_create_object;
165239
curl_share_ce->default_object_handlers = &curl_share_handlers;
166240

@@ -170,4 +244,6 @@ void curl_share_register_handlers(void) {
170244
curl_share_handlers.get_constructor = curl_share_get_constructor;
171245
curl_share_handlers.clone_obj = NULL;
172246
curl_share_handlers.compare = zend_objects_not_comparable;
247+
248+
le_pcurlsh = zend_register_list_destructors_ex(NULL, php_pcurlsh_dtor, "Curl persistent shared handle", module_number);
173249
}

0 commit comments

Comments
 (0)