Skip to content

Commit e746ee3

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

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
@@ -478,12 +478,16 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n)
478478
}
479479

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

485487
if (curl->handlers.write_header) {
486-
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->func_name);
488+
if (ZEND_FCC_INITIALIZED(curl->handlers.write_header->fcc)) {
489+
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write_header->fcc);
490+
}
487491
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->stream);
488492
}
489493

@@ -562,51 +566,39 @@ static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ct
562566
static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
563567
{
564568
php_curl *ch = (php_curl *) ctx;
565-
php_curl_write *t = ch->handlers.write;
569+
php_curl_write *write_handler = ch->handlers.write;
566570
size_t length = size * nmemb;
567571

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

573-
switch (t->method) {
577+
switch (write_handler->method) {
574578
case PHP_CURL_STDOUT:
575579
PHPWRITE(data, length);
576580
break;
577581
case PHP_CURL_FILE:
578-
return fwrite(data, size, nmemb, t->fp);
582+
return fwrite(data, size, nmemb, write_handler->fp);
579583
case PHP_CURL_RETURN:
580584
if (length > 0) {
581-
smart_str_appendl(&t->buf, data, (int) length);
585+
smart_str_appendl(&write_handler->buf, data, (int) length);
582586
}
583587
break;
584588
case PHP_CURL_USER: {
585589
zval argv[2];
586590
zval retval;
587-
int error;
588-
zend_fcall_info fci;
589591

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

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

@@ -837,10 +829,10 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
837829
static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
838830
{
839831
php_curl *ch = (php_curl *) ctx;
840-
php_curl_write *t = ch->handlers.write_header;
832+
php_curl_write *write_handler = ch->handlers.write_header;
841833
size_t length = size * nmemb;
842834

843-
switch (t->method) {
835+
switch (write_handler->method) {
844836
case PHP_CURL_STDOUT:
845837
/* Handle special case write when we're returning the entire transfer
846838
*/
@@ -851,32 +843,20 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
851843
}
852844
break;
853845
case PHP_CURL_FILE:
854-
return fwrite(data, size, nmemb, t->fp);
846+
return fwrite(data, size, nmemb, write_handler->fp);
855847
case PHP_CURL_USER: {
856848
zval argv[2];
857849
zval retval;
858-
zend_result error;
859-
zend_fcall_info fci;
860850

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

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

1172-
if (!Z_ISUNDEF(source->handlers.write->func_name)) {
1173-
ZVAL_COPY(&ch->handlers.write->func_name, &source->handlers.write->func_name);
1174-
}
11751152
if (!Z_ISUNDEF(source->handlers.read->func_name)) {
11761153
ZVAL_COPY(&ch->handlers.read->func_name, &source->handlers.read->func_name);
11771154
}
1178-
if (!Z_ISUNDEF(source->handlers.write_header->func_name)) {
1179-
ZVAL_COPY(&ch->handlers.write_header->func_name, &source->handlers.write_header->func_name);
1155+
if (ZEND_FCC_INITIALIZED(source->handlers.write->fcc)) {
1156+
zend_fcc_dup(&source->handlers.write->fcc, &source->handlers.write->fcc);
1157+
}
1158+
if (ZEND_FCC_INITIALIZED(source->handlers.write_header->fcc)) {
1159+
zend_fcc_dup(&source->handlers.write_header->fcc, &source->handlers.write_header->fcc);
11801160
}
1161+
php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);
1162+
php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);
11811163

11821164
curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str);
11831165
curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch);
@@ -2024,15 +2006,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20242006
error = curl_easy_setopt(ch->cp, option, lval);
20252007
break;
20262008

2027-
case CURLOPT_HEADERFUNCTION:
2028-
if (!Z_ISUNDEF(ch->handlers.write_header->func_name)) {
2029-
zval_ptr_dtor(&ch->handlers.write_header->func_name);
2030-
ch->handlers.write_header->fci_cache = empty_fcall_info_cache;
2031-
}
2032-
ZVAL_COPY(&ch->handlers.write_header->func_name, zvalue);
2033-
ch->handlers.write_header->method = PHP_CURL_USER;
2034-
break;
2035-
20362009
case CURLOPT_POSTFIELDS:
20372010
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
20382011
if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
@@ -2053,6 +2026,28 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20532026
}
20542027
break;
20552028

2029+
case CURLOPT_WRITEFUNCTION: {
2030+
/* Check value is actually a callable and set it */
2031+
const char option_name[] = "CURLOPT_WRITEFUNCTION";
2032+
bool result = php_curl_set_callable_handler(&ch->handlers.write->fcc, zvalue, is_array_config, option_name);
2033+
if (!result) {
2034+
return FAILURE;
2035+
}
2036+
ch->handlers.write->method = PHP_CURL_USER;
2037+
break;
2038+
}
2039+
2040+
case CURLOPT_HEADERFUNCTION: {
2041+
/* Check value is actually a callable and set it */
2042+
const char option_name[] = "CURLOPT_HEADERFUNCTION";
2043+
bool result = php_curl_set_callable_handler(&ch->handlers.write_header->fcc, zvalue, is_array_config, option_name);
2044+
if (!result) {
2045+
return FAILURE;
2046+
}
2047+
ch->handlers.write_header->method = PHP_CURL_USER;
2048+
break;
2049+
}
2050+
20562051
case CURLOPT_PROGRESSFUNCTION: {
20572052
/* Check value is actually a callable and set it */
20582053
const char option_name[] = "CURLOPT_PROGRESSFUNCTION";
@@ -2120,15 +2115,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
21202115
}
21212116
break;
21222117

2123-
case CURLOPT_WRITEFUNCTION:
2124-
if (!Z_ISUNDEF(ch->handlers.write->func_name)) {
2125-
zval_ptr_dtor(&ch->handlers.write->func_name);
2126-
ch->handlers.write->fci_cache = empty_fcall_info_cache;
2127-
}
2128-
ZVAL_COPY(&ch->handlers.write->func_name, zvalue);
2129-
ch->handlers.write->method = PHP_CURL_USER;
2130-
break;
2131-
21322118
/* Curl off_t options */
21332119
case CURLOPT_MAX_RECV_SPEED_LARGE:
21342120
case CURLOPT_MAX_SEND_SPEED_LARGE:
@@ -2730,9 +2716,13 @@ static void curl_free_obj(zend_object *object)
27302716
}
27312717

27322718
smart_str_free(&ch->handlers.write->buf);
2733-
zval_ptr_dtor(&ch->handlers.write->func_name);
27342719
zval_ptr_dtor(&ch->handlers.read->func_name);
2735-
zval_ptr_dtor(&ch->handlers.write_header->func_name);
2720+
if (ZEND_FCC_INITIALIZED(ch->handlers.write->fcc)) {
2721+
zend_fcc_dtor(&ch->handlers.write->fcc);
2722+
}
2723+
if (ZEND_FCC_INITIALIZED(ch->handlers.write_header->fcc)) {
2724+
zend_fcc_dtor(&ch->handlers.write_header->fcc);
2725+
}
27362726
zval_ptr_dtor(&ch->handlers.std_err);
27372727
if (ch->header.str) {
27382728
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)