Skip to content

Commit b7f8a34

Browse files
committed
ext/curl: Convert php_curl_write to just use FCC without a function name zval
1 parent 2039af4 commit b7f8a34

File tree

3 files changed

+65
-70
lines changed

3 files changed

+65
-70
lines changed

ext/curl/curl_private.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ PHP_MSHUTDOWN_FUNCTION(curl);
4545
PHP_MINFO_FUNCTION(curl);
4646

4747
typedef struct {
48-
zval func_name;
49-
zend_fcall_info_cache fci_cache;
48+
zend_fcall_info_cache fcc;
5049
FILE *fp;
5150
smart_str buf;
5251
int method;

ext/curl/interface.c

Lines changed: 58 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -479,12 +479,16 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n)
479479
}
480480

481481
if (curl->handlers.write) {
482-
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write->func_name);
482+
if (ZEND_FCC_INITIALIZED(curl->handlers.write->fcc)) {
483+
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write->fcc);
484+
}
483485
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write->stream);
484486
}
485487

486488
if (curl->handlers.write_header) {
487-
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->func_name);
489+
if (ZEND_FCC_INITIALIZED(curl->handlers.write_header->fcc)) {
490+
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write_header->fcc);
491+
}
488492
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->stream);
489493
}
490494

@@ -563,51 +567,39 @@ static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ct
563567
static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
564568
{
565569
php_curl *ch = (php_curl *) ctx;
566-
php_curl_write *t = ch->handlers.write;
570+
php_curl_write *write_handler = ch->handlers.write;
567571
size_t length = size * nmemb;
568572

569573
#if PHP_CURL_DEBUG
570574
fprintf(stderr, "curl_write() called\n");
571575
fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n", data, size, nmemb, ctx);
572576
#endif
573577

574-
switch (t->method) {
578+
switch (write_handler->method) {
575579
case PHP_CURL_STDOUT:
576580
PHPWRITE(data, length);
577581
break;
578582
case PHP_CURL_FILE:
579-
return fwrite(data, size, nmemb, t->fp);
583+
return fwrite(data, size, nmemb, write_handler->fp);
580584
case PHP_CURL_RETURN:
581585
if (length > 0) {
582-
smart_str_appendl(&t->buf, data, (int) length);
586+
smart_str_appendl(&write_handler->buf, data, (int) length);
583587
}
584588
break;
585589
case PHP_CURL_USER: {
586590
zval argv[2];
587591
zval retval;
588-
int error;
589-
zend_fcall_info fci;
590592

591593
GC_ADDREF(&ch->std);
592594
ZVAL_OBJ(&argv[0], &ch->std);
593595
ZVAL_STRINGL(&argv[1], data, length);
594596

595-
fci.size = sizeof(fci);
596-
fci.object = NULL;
597-
ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
598-
fci.retval = &retval;
599-
fci.param_count = 2;
600-
fci.params = argv;
601-
fci.named_params = NULL;
602-
603-
ch->in_callback = 1;
604-
error = zend_call_function(&fci, &t->fci_cache);
605-
ch->in_callback = 0;
606-
if (error == FAILURE) {
607-
php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_WRITEFUNCTION");
608-
length = -1;
609-
} else if (!Z_ISUNDEF(retval)) {
597+
ch->in_callback = true;
598+
zend_call_known_fcc(&write_handler->fcc, &retval, /* param_count */ 2, argv, /* named_params */ NULL);
599+
ch->in_callback = false;
600+
if (!Z_ISUNDEF(retval)) {
610601
_php_curl_verify_handlers(ch, /* reporterror */ true);
602+
/* TODO Check callback returns an int or something castable to int */
611603
length = zval_get_long(&retval);
612604
}
613605

@@ -838,10 +830,10 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
838830
static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
839831
{
840832
php_curl *ch = (php_curl *) ctx;
841-
php_curl_write *t = ch->handlers.write_header;
833+
php_curl_write *write_handler = ch->handlers.write_header;
842834
size_t length = size * nmemb;
843835

844-
switch (t->method) {
836+
switch (write_handler->method) {
845837
case PHP_CURL_STDOUT:
846838
/* Handle special case write when we're returning the entire transfer
847839
*/
@@ -852,32 +844,20 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
852844
}
853845
break;
854846
case PHP_CURL_FILE:
855-
return fwrite(data, size, nmemb, t->fp);
847+
return fwrite(data, size, nmemb, write_handler->fp);
856848
case PHP_CURL_USER: {
857849
zval argv[2];
858850
zval retval;
859-
zend_result error;
860-
zend_fcall_info fci;
861851

862852
GC_ADDREF(&ch->std);
863853
ZVAL_OBJ(&argv[0], &ch->std);
864854
ZVAL_STRINGL(&argv[1], data, length);
865855

866-
fci.size = sizeof(fci);
867-
ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
868-
fci.object = NULL;
869-
fci.retval = &retval;
870-
fci.param_count = 2;
871-
fci.params = argv;
872-
fci.named_params = NULL;
873-
874-
ch->in_callback = 1;
875-
error = zend_call_function(&fci, &t->fci_cache);
876-
ch->in_callback = 0;
877-
if (error == FAILURE) {
878-
php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_HEADERFUNCTION");
879-
length = -1;
880-
} else if (!Z_ISUNDEF(retval)) {
856+
ch->in_callback = true;
857+
zend_call_known_fcc(&write_handler->fcc, &retval, /* param_count */ 2, argv, /* named_params */ NULL);
858+
ch->in_callback = false;
859+
if (!Z_ISUNDEF(retval)) {
860+
// TODO: Check for valid int type for return value
881861
_php_curl_verify_handlers(ch, /* reporterror */ true);
882862
length = zval_get_long(&retval);
883863
}
@@ -1232,15 +1212,17 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
12321212
ch->handlers.read->fp = source->handlers.read->fp;
12331213
ch->handlers.read->res = source->handlers.read->res;
12341214

1235-
if (!Z_ISUNDEF(source->handlers.write->func_name)) {
1236-
ZVAL_COPY(&ch->handlers.write->func_name, &source->handlers.write->func_name);
1237-
}
12381215
if (!Z_ISUNDEF(source->handlers.read->func_name)) {
12391216
ZVAL_COPY(&ch->handlers.read->func_name, &source->handlers.read->func_name);
12401217
}
1241-
if (!Z_ISUNDEF(source->handlers.write_header->func_name)) {
1242-
ZVAL_COPY(&ch->handlers.write_header->func_name, &source->handlers.write_header->func_name);
1218+
if (ZEND_FCC_INITIALIZED(source->handlers.write->fcc)) {
1219+
zend_fcc_dup(&source->handlers.write->fcc, &source->handlers.write->fcc);
1220+
}
1221+
if (ZEND_FCC_INITIALIZED(source->handlers.write_header->fcc)) {
1222+
zend_fcc_dup(&source->handlers.write_header->fcc, &source->handlers.write_header->fcc);
12431223
}
1224+
php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);
1225+
php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);
12441226

12451227
curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str);
12461228
curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
@@ -2087,15 +2069,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20872069
error = curl_easy_setopt(ch->cp, option, lval);
20882070
break;
20892071

2090-
case CURLOPT_HEADERFUNCTION:
2091-
if (!Z_ISUNDEF(ch->handlers.write_header->func_name)) {
2092-
zval_ptr_dtor(&ch->handlers.write_header->func_name);
2093-
ch->handlers.write_header->fci_cache = empty_fcall_info_cache;
2094-
}
2095-
ZVAL_COPY(&ch->handlers.write_header->func_name, zvalue);
2096-
ch->handlers.write_header->method = PHP_CURL_USER;
2097-
break;
2098-
20992072
case CURLOPT_POSTFIELDS:
21002073
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
21012074
if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
@@ -2116,6 +2089,28 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
21162089
}
21172090
break;
21182091

2092+
case CURLOPT_WRITEFUNCTION: {
2093+
/* Check value is actually a callable and set it */
2094+
const char option_name[] = "CURLOPT_WRITEFUNCTION";
2095+
bool result = php_curl_set_callable_handler(&ch->handlers.write->fcc, zvalue, is_array_config, option_name);
2096+
if (!result) {
2097+
return FAILURE;
2098+
}
2099+
ch->handlers.write->method = PHP_CURL_USER;
2100+
break;
2101+
}
2102+
2103+
case CURLOPT_HEADERFUNCTION: {
2104+
/* Check value is actually a callable and set it */
2105+
const char option_name[] = "CURLOPT_HEADERFUNCTION";
2106+
bool result = php_curl_set_callable_handler(&ch->handlers.write_header->fcc, zvalue, is_array_config, option_name);
2107+
if (!result) {
2108+
return FAILURE;
2109+
}
2110+
ch->handlers.write_header->method = PHP_CURL_USER;
2111+
break;
2112+
}
2113+
21192114
case CURLOPT_PROGRESSFUNCTION: {
21202115
/* Check value is actually a callable and set it */
21212116
const char option_name[] = "CURLOPT_PROGRESSFUNCTION";
@@ -2183,15 +2178,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
21832178
}
21842179
break;
21852180

2186-
case CURLOPT_WRITEFUNCTION:
2187-
if (!Z_ISUNDEF(ch->handlers.write->func_name)) {
2188-
zval_ptr_dtor(&ch->handlers.write->func_name);
2189-
ch->handlers.write->fci_cache = empty_fcall_info_cache;
2190-
}
2191-
ZVAL_COPY(&ch->handlers.write->func_name, zvalue);
2192-
ch->handlers.write->method = PHP_CURL_USER;
2193-
break;
2194-
21952181
/* Curl off_t options */
21962182
case CURLOPT_MAX_RECV_SPEED_LARGE:
21972183
case CURLOPT_MAX_SEND_SPEED_LARGE:
@@ -2793,9 +2779,13 @@ static void curl_free_obj(zend_object *object)
27932779
}
27942780

27952781
smart_str_free(&ch->handlers.write->buf);
2796-
zval_ptr_dtor(&ch->handlers.write->func_name);
27972782
zval_ptr_dtor(&ch->handlers.read->func_name);
2798-
zval_ptr_dtor(&ch->handlers.write_header->func_name);
2783+
if (ZEND_FCC_INITIALIZED(ch->handlers.write->fcc)) {
2784+
zend_fcc_dtor(&ch->handlers.write->fcc);
2785+
}
2786+
if (ZEND_FCC_INITIALIZED(ch->handlers.write_header->fcc)) {
2787+
zend_fcc_dtor(&ch->handlers.write_header->fcc);
2788+
}
27992789
zval_ptr_dtor(&ch->handlers.std_err);
28002790
if (ch->header.str) {
28012791
zend_string_release_ex(ch->header.str, 0);

ext/curl/tests/curl_setopt_callables.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ testOption($ch, CURLOPT_PROGRESSFUNCTION);
2727
testOption($ch, CURLOPT_SSH_HOSTKEYFUNCTION);
2828
testOption($ch, CURLOPT_XFERINFOFUNCTION);
2929
testOption($ch, CURLOPT_FNMATCH_FUNCTION);
30+
testOption($ch, CURLOPT_WRITEFUNCTION);
31+
testOption($ch, CURLOPT_HEADERFUNCTION);
3032

3133
?>
3234
--EXPECT--
@@ -38,3 +40,7 @@ TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for opti
3840
TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_XFERINFOFUNCTION, function "undefined" not found or invalid function name
3941
TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_FNMATCH_FUNCTION, function "undefined" not found or invalid function name
4042
TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_FNMATCH_FUNCTION, function "undefined" not found or invalid function name
43+
TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_WRITEFUNCTION, function "undefined" not found or invalid function name
44+
TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_WRITEFUNCTION, function "undefined" not found or invalid function name
45+
TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_HEADERFUNCTION, function "undefined" not found or invalid function name
46+
TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_HEADERFUNCTION, function "undefined" not found or invalid function name

0 commit comments

Comments
 (0)