8000 ext/curl: Refactor cURL to only use FCC by Girgias · Pull Request #13291 · php/php-src · GitHub
[go: up one dir, main page]

Skip to content

ext/curl: Refactor cURL to only use FCC #13291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
ext/curl: Convert php_curl_write to just use FCC without a function n…
…ame zval
  • Loading branch information
Girgias committed Apr 30, 2024
commit cf9228fd92b6ceb48957601772cec9dc30bbcdda
3 changes: 1 addition & 2 deletions ext/curl/curl_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ PHP_MSHUTDOWN_FUNCTION(curl);
PHP_MINFO_FUNCTION(curl);

typedef struct {
zval func_name;
zend_fcall_info_cache fci_cache;
zend_fcall_info_cache fcc;
FILE *fp;
smart_str buf;
int method;
Expand Down
126 changes: 58 additions & 68 deletions ext/curl/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,16 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n)
}

if (curl->handlers.write) {
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write->func_name);
if (ZEND_FCC_INITIALIZED(curl->handlers.write->fcc)) {
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write->fcc);
}
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write->stream);
}

if (curl->handlers.write_header) {
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->func_name);
if (ZEND_FCC_INITIALIZED(curl->handlers.write_header->fcc)) {
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.write_header->fcc);
}
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->stream);
}

Expand Down Expand Up @@ -563,51 +567,39 @@ static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ct
static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
{
php_curl *ch = (php_curl *) ctx;
php_curl_write *t = ch->handlers.write;
php_curl_write *write_handler = ch->handlers.write;
size_t length = size * nmemb;

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

switch (t->method) {
switch (write_handler->method) {
case PHP_CURL_STDOUT:
PHPWRITE(data, length);
break;
case PHP_CURL_FILE:
return fwrite(data, size, nmemb, t->fp);
return fwrite(data, size, nmemb, write_handler->fp);
case PHP_CURL_RETURN:
if (length > 0) {
smart_str_appendl(&t->buf, data, (int) length);
smart_str_appendl(&write_handler->buf, data, (int) length);
}
break;
case PHP_CURL_USER: {
zval argv[2];
zval retval;
int error;
zend_fcall_info fci;

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

fci.size = sizeof(fci);
fci.object = NULL;
ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
fci.retval = &retval;
fci.param_count = 2;
fci.params = argv;
fci.named_params = NULL;

ch->in_callback = 1;
error = zend_call_function(&fci, &t->fci_cache);
ch->in_callback = 0;
if (error == FAILURE) {
php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_WRITEFUNCTION");
length = -1;
} else if (!Z_ISUNDEF(retval)) {
ch->in_callback = true;
zend_call_known_fcc(&write_handler->fcc, &retval, /* param_count */ 2, argv, /* named_params */ NULL);
ch->in_callback = false;
if (!Z_ISUNDEF(retval)) {
_php_curl_verify_handlers(ch, /* reporterror */ true);
/* TODO Check callback returns an int or something castable to int */
length = zval_get_long(&retval);
}

Expand Down Expand Up @@ -838,10 +830,10 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx)
{
php_curl *ch = (php_curl *) ctx;
php_curl_write *t = ch->handlers.write_header;
php_curl_write *write_handler = ch->handlers.write_header;
size_t length = size * nmemb;

switch (t->method) {
switch (write_handler->method) {
case PHP_CURL_STDOUT:
/* Handle special case write when we're returning the entire transfer
*/
Expand All @@ -852,32 +844,20 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
}
break;
case PHP_CURL_FILE:
return fwrite(data, size, nmemb, t->fp);
return fwrite(data, size, nmemb, write_handler->fp);
case PHP_CURL_USER: {
zval argv[2];
zval retval;
zend_result error;
zend_fcall_info fci;

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

fci.size = sizeof(fci);
ZVAL_COPY_VALUE(&fci.function_name, &t->func_name);
fci.object = NULL;
fci.retval = &retval;
fci.param_count = 2;
fci.params = argv;
fci.named_params = NULL;

ch->in_callback = 1;
error = zend_call_function(&fci, &t->fci_cache);
ch->in_callback = 0;
if (error == FAILURE) {
php_error_docref(NULL, E_WARNING, "Could not call the CURLOPT_HEADERFUNCTION");
length = -1;
} else if (!Z_ISUNDEF(retval)) {
ch->in_callback = true;
zend_call_known_fcc(&write_handler->fcc, &retval, /* param_count */ 2, argv, /* named_params */ NULL);
ch->in_callback = false;
if (!Z_ISUNDEF(retval)) {
// TODO: Check for valid int type for return value
_php_curl_verify_handlers(ch, /* reporterror */ true);
length = zval_get_long(&retval);
}
Expand Down Expand Up @@ -1232,15 +1212,17 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
ch->handlers.read->fp = source->handlers.read->fp;
ch->handlers.read->res = source->handlers.read->res;

if (!Z_ISUNDEF(source->handlers.write->func_name)) {
ZVAL_COPY(&ch->handlers.write->func_name, &source->handlers.write->func_name);
}
if (!Z_ISUNDEF(source->handlers.read->func_name)) {
ZVAL_COPY(&ch->handlers.read->func_name, &source->handlers.read->func_name);
}
if (!Z_ISUNDEF(source->handlers.write_header->func_name)) {
ZVAL_COPY(&ch->handlers.write_header->func_name, &source->handlers.write_header->func_name);
if (ZEND_FCC_INITIALIZED(source->handlers.write->fcc)) {
zend_fcc_dup(&source->handlers.write->fcc, &source->handlers.write->fcc);
}
if (ZEND_FCC_INITIALIZED(source->handlers.write_header->fcc)) {
zend_fcc_dup(&source->handlers.write_header->fcc, &source->handlers.write_header->fcc);
}
php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);
php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo);

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

case CURLOPT_HEADERFUNCTION:
if (!Z_ISUNDEF(ch->handlers.write_header->func_name)) {
zval_ptr_dtor(&ch->handlers.write_header->func_name);
ch->handlers.write_header->fci_cache = empty_fcall_info_cache;
}
ZVAL_COPY(&ch->handlers.write_header->func_name, zvalue);
ch->handlers.write_header->method = PHP_CURL_USER;
break;

case CURLOPT_POSTFIELDS:
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
Expand All @@ -2116,6 +2089,28 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
}
break;

case CURLOPT_WRITEFUNCTION: {
/* Check value is actually a callable and set it */
const char option_name[] = "CURLOPT_WRITEFUNCTION";
bool result = php_curl_set_callable_handler(&ch->handlers.write->fcc, zvalue, is_array_config, option_name);
if (!result) {
return FAILURE;
}
ch->handlers.write->method = PHP_CURL_USER;
break;
}

case CURLOPT_HEADERFUNCTION: {
/* Check value is actually a callable and set it */
const char option_name[] = "CURLOPT_HEADERFUNCTION";
bool result = php_curl_set_callable_handler(&ch->handlers.write_header->fcc, zvalue, is_array_config, option_name);
if (!result) {
return FAILURE;
}
ch->handlers.write_header->method = PHP_CURL_USER;
break;
}

case CURLOPT_PROGRESSFUNCTION: {
/* Check value is actually a callable and set it */
const char option_name[] = "CURLOPT_PROGRESSFUNCTION";
Expand Down Expand Up @@ -2183,15 +2178,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
}
break;

case CURLOPT_WRITEFUNCTION:
if (!Z_ISUNDEF(ch->handlers.write->func_name)) {
zval_ptr_dtor(&ch->handlers.write->func_name);
ch->handlers.write->fci_cache = empty_fcall_info_cache;
}
ZVAL_COPY(&ch->handlers.write->func_name, zvalue);
ch->handlers.write->method = PHP_CURL_USER;
break;

/* Curl off_t options */
case CURLOPT_MAX_RECV_SPEED_LARGE:
case CURLOPT_MAX_SEND_SPEED_LARGE:
Expand Down Expand Up @@ -2793,9 +2779,13 @@ static void curl_free_obj(zend_object *object)
}

smart_str_free(&ch->handlers.write->buf);
zval_ptr_dtor(&ch->handlers.write->func_name);
zval_ptr_dtor(&ch->handlers.read->func_name);
zval_ptr_dtor(&ch->handlers.write_header->func_name);
if (ZEND_FCC_INITIALIZED(ch->handlers.write->fcc)) {
zend_fcc_dtor(&ch->handlers.write->fcc);
}
if (ZEND_FCC_INITIALIZED(ch->handlers.write_header->fcc)) {
zend_fcc_dtor(&ch->handlers.write_header->fcc);
}
zval_ptr_dtor(&ch->handlers.std_err);
if (ch->header.str) {
zend_string_release_ex(ch->header.str, 0);
Expand Down
6 changes: 6 additions & 0 deletions ext/curl/tests/curl_setopt_callables.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ testOption($ch, CURLOPT_PROGRESSFUNCTION);
testOption($ch, CURLOPT_SSH_HOSTKEYFUNCTION);
testOption($ch, CURLOPT_XFERINFOFUNCTION);
testOption($ch, CURLOPT_FNMATCH_FUNCTION);
testOption($ch, CURLOPT_WRITEFUNCTION);
testOption($ch, CURLOPT_HEADERFUNCTION);

?>
--EXPECT--
Expand All @@ -38,3 +40,7 @@ TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for opti
TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_XFERINFOFUNCTION, function "undefined" not found or invalid function name
TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_FNMATCH_FUNCTION, function "undefined" not found or invalid function name
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
TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_WRITEFUNCTION, function "undefined" not found or invalid function name
TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_WRITEFUNCTION, function "undefined" not found or invalid function name
TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_HEADERFUNCTION, function "undefined" not found or invalid function name
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