diff --git a/ext/curl/curl_private.h b/ext/curl/curl_private.h index aeef5937a0de8..c15396f255b17 100644 --- a/ext/curl/curl_private.h +++ b/ext/curl/curl_private.h @@ -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; @@ -54,29 +53,23 @@ typedef struct { } php_curl_write; typedef struct { - zval func_name; - zend_fcall_info_cache fci_cache; + zend_fcall_info_cache fcc; FILE *fp; zend_resource *res; int method; zval stream; } php_curl_read; -typedef struct { - zval func_name; - zend_fcall_info_cache fci_cache; -} php_curl_callback; - typedef struct { php_curl_write *write; php_curl_write *write_header; php_curl_read *read; zval std_err; - php_curl_callback *progress; - php_curl_callback *xferinfo; - php_curl_callback *fnmatch; + zend_fcall_info_cache progress; + zend_fcall_info_cache xferinfo; + zend_fcall_info_cache fnmatch; #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - php_curl_callback *sshhostkey; + zend_fcall_info_cache sshhostkey; #endif } php_curl_handlers; @@ -114,7 +107,7 @@ typedef struct { #define CURLOPT_SAFE_UPLOAD -1 typedef struct { - php_curl_callback *server_push; + zend_fcall_info_cache server_push; } php_curlm_handlers; typedef struct { diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 60481947dddea..59362adddb7bd 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -474,35 +474,41 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer_add_zval(gc_buffer, &curl->postfields); if (curl->handlers.read) { - zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.read->func_name); + if (ZEND_FCC_INITIALIZED(curl->handlers.read->fcc)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.read->fcc); + } zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.read->stream); } 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); } - if (curl->handlers.progress) { - zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.progress->func_name); + if (ZEND_FCC_INITIALIZED(curl->handlers.progress)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.progress); } - if (curl->handlers.xferinfo) { - zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.xferinfo->func_name); + if (ZEND_FCC_INITIALIZED(curl->handlers.xferinfo)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.xferinfo); } - if (curl->handlers.fnmatch) { - zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.fnmatch->func_name); + if (ZEND_FCC_INITIALIZED(curl->handlers.fnmatch)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.fnmatch); } #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - if (curl->handlers.sshhostkey) { - zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.sshhostkey->func_name); + if (ZEND_FCC_INITIALIZED(curl->handlers.sshhostkey)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.sshhostkey); } #endif @@ -550,20 +556,11 @@ PHP_MSHUTDOWN_FUNCTION(curl) } /* }}} */ -/* {{{ curl_write_nothing - * Used as a work around. See _php_curl_close_ex - */ -static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx) -{ - return size * nmemb; -} -/* }}} */ - /* {{{ curl_write */ 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 @@ -571,43 +568,31 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) 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); } @@ -625,33 +610,22 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) static int curl_fnmatch(void *ctx, const char *pattern, const char *string) { php_curl *ch = (php_curl *) ctx; - php_curl_callback *t = ch->handlers.fnmatch; int rval = CURL_FNMATCHFUNC_FAIL; zval argv[3]; zval retval; - zend_result error; - zend_fcall_info fci; GC_ADDREF(&ch->std); ZVAL_OBJ(&argv[0], &ch->std); ZVAL_STRING(&argv[1], pattern); ZVAL_STRING(&argv[2], string); - fci.size = sizeof(fci); - ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = 3; - 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, "Cannot call the CURLOPT_FNMATCH_FUNCTION"); - } else if (!Z_ISUNDEF(retval)) { + ch->in_callback = true; + zend_call_known_fcc(&ch->handlers.fnmatch, &retval, /* param_count */ 3, 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 */ rval = zval_get_long(&retval); } zval_ptr_dtor(&argv[0]); @@ -665,7 +639,6 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string) static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { php_curl *ch = (php_curl *)clientp; - php_curl_callback *t = ch->handlers.progress; size_t rval = 0; #if PHP_CURL_DEBUG @@ -673,38 +646,29 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow); #endif - zval argv[5]; + zval args[5]; zval retval; - zend_result error; - zend_fcall_info fci; GC_ADDREF(&ch->std); - ZVAL_OBJ(&argv[0], &ch->std); - ZVAL_LONG(&argv[1], (zend_long)dltotal); - ZVAL_LONG(&argv[2], (zend_long)dlnow); - ZVAL_LONG(&argv[3], (zend_long)ultotal); - ZVAL_LONG(&argv[4], (zend_long)ulnow); - - fci.size = sizeof(fci); - ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = 5; - 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, "Cannot call the CURLOPT_PROGRESSFUNCTION"); - } else if (!Z_ISUNDEF(retval)) { + ZVAL_OBJ(&args[0], &ch->std); + ZVAL_LONG(&args[1], (zend_long)dltotal); + ZVAL_LONG(&args[2], (zend_long)dlnow); + ZVAL_LONG(&args[3], (zend_long)ultotal); + ZVAL_LONG(&args[4], (zend_long)ulnow); + + ch->in_callback = true; + zend_call_known_fcc(&ch->handlers.progress, &retval, /* param_count */ 5, args, /* 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 */ if (0 != zval_get_long(&retval)) { rval = 1; } } - zval_ptr_dtor(&argv[0]); + + zval_ptr_dtor(&args[0]); return rval; } /* }}} */ @@ -713,7 +677,6 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { php_curl *ch = (php_curl *)clientp; - php_curl_callback *t = ch->handlers.xferinfo; size_t rval = 0; #if PHP_CURL_DEBUG @@ -723,8 +686,6 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, zval argv[5]; zval retval; - zend_result error; - zend_fcall_info fci; GC_ADDREF(&ch->std); ZVAL_OBJ(&argv[0], &ch->std); @@ -733,25 +694,18 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, ZVAL_LONG(&argv[3], ultotal); ZVAL_LONG(&argv[4], ulnow); - fci.size = sizeof(fci); - ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = 5; - 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, "Cannot call the CURLOPT_XFERINFOFUNCTION"); - } else if (!Z_ISUNDEF(retval)) { + ch->in_callback = true; + zend_call_known_fcc(&ch->handlers.xferinfo, &retval, /* param_count */ 5, 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 */ if (0 != zval_get_long(&retval)) { rval = 1; } } + zval_ptr_dtor(&argv[0]); return rval; } @@ -761,7 +715,6 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, size_t keylen) { php_curl *ch = (php_curl *)clientp; - php_curl_callback *t = ch->handlers.sshhostkey; int rval = CURLKHMATCH_MISMATCH; /* cancel connection in case of an exception */ #if PHP_CURL_DEBUG @@ -769,31 +722,20 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, fprintf(stderr, "clientp = %x, keytype = %d, key = %s, keylen = %zu\n", clientp, keytype, key, keylen); #endif - zval argv[4]; + zval args[4]; zval retval; - zend_result error; - zend_fcall_info fci; GC_ADDREF(&ch->std); - ZVAL_OBJ(&argv[0], &ch->std); - ZVAL_LONG(&argv[1], keytype); - ZVAL_STRINGL(&argv[2], key, keylen); - ZVAL_LONG(&argv[3], keylen); - - fci.size = sizeof(fci); - ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = 4; - 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, "Cannot call the CURLOPT_SSH_HOSTKEYFUNCTION"); - } else if (!Z_ISUNDEF(retval)) { + ZVAL_OBJ(&args[0], &ch->std); + ZVAL_LONG(&args[1], keytype); + ZVAL_STRINGL(&args[2], key, keylen); + ZVAL_LONG(&args[3], keylen); + + ch->in_callback = true; + zend_call_known_fcc(&ch->handlers.sshhostkey, &retval, /* param_count */ 4, args, /* named_params */ NULL); + ch->in_callback = false; + + if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); if (Z_TYPE(retval) == IS_LONG) { zend_long retval_long = Z_LVAL(retval); @@ -806,8 +748,9 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, zend_throw_error(NULL, "The CURLOPT_SSH_HOSTKEYFUNCTION callback must return either CURLKHMATCH_OK or CURLKHMATCH_MISMATCH"); } } - zval_ptr_dtor(&argv[0]); - zval_ptr_dtor(&argv[2]); + + zval_ptr_dtor(&args[0]); + zval_ptr_dtor(&args[2]); return rval; } #endif @@ -816,46 +759,33 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) { php_curl *ch = (php_curl *)ctx; - php_curl_read *t = ch->handlers.read; + php_curl_read *read_handler = ch->handlers.read; int length = 0; - switch (t->method) { + switch (read_handler->method) { case PHP_CURL_DIRECT: - if (t->fp) { - length = fread(data, size, nmemb, t->fp); + if (read_handler->fp) { + length = fread(data, size, nmemb, read_handler->fp); } break; case PHP_CURL_USER: { zval argv[3]; zval retval; - zend_result error; - zend_fcall_info fci; GC_ADDREF(&ch->std); ZVAL_OBJ(&argv[0], &ch->std); - if (t->res) { - GC_ADDREF(t->res); - ZVAL_RES(&argv[1], t->res); + if (read_handler->res) { + GC_ADDREF(read_handler->res); + ZVAL_RES(&argv[1], read_handler->res); } else { ZVAL_NULL(&argv[1]); } ZVAL_LONG(&argv[2], (int)size * nmemb); - fci.size = sizeof(fci); - ZVAL_COPY_VALUE(&fci.function_name, &t->func_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = 3; - 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, "Cannot call the CURLOPT_READFUNCTION"); - length = CURL_READFUNC_ABORT; - } else if (!Z_ISUNDEF(retval)) { + ch->in_callback = true; + zend_call_known_fcc(&read_handler->fcc, &retval, /* param_count */ 3, argv, /* named_params */ NULL); + ch->in_callback = false; + if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); if (Z_TYPE(retval) == IS_STRING) { length = MIN((int) (size * nmemb), Z_STRLEN(retval)); @@ -863,6 +793,7 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) } else if (Z_TYPE(retval) == IS_LONG) { length = Z_LVAL_P(&retval); } + // TODO Do type error if invalid type? zval_ptr_dtor(&retval); } @@ -880,10 +811,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 */ @@ -894,32 +825,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); } @@ -1004,8 +923,8 @@ PHP_FUNCTION(curl_version) /* Add an array of features */ { struct feat { - const char *name; - int bitmask; + const char *name; + int bitmask; }; unsigned int i; @@ -1055,7 +974,7 @@ PHP_FUNCTION(curl_version) #endif }; - for(i = 0; i < sizeof(feats) / sizeof(feats[0]); i++) { + for(i = 0; i < sizeof(feats) / sizeof(feats[0]); i++) { if (feats[i].name) { add_assoc_bool(&feature_list, feats[i].name, d->features & feats[i].bitmask ? true : false); } @@ -1117,11 +1036,11 @@ void init_curl_handle(php_curl *ch) ch->handlers.write = ecalloc(1, sizeof(php_curl_write)); ch->handlers.write_header = ecalloc(1, sizeof(php_curl_write)); ch->handlers.read = ecalloc(1, sizeof(php_curl_read)); - ch->handlers.progress = NULL; - ch->handlers.xferinfo = NULL; - ch->handlers.fnmatch = NULL; + ch->handlers.progress = empty_fcall_info_cache; + ch->handlers.xferinfo = empty_fcall_info_cache; + ch->handlers.fnmatch = empty_fcall_info_cache; #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - ch->handlers.sshhostkey = NULL; + ch->handlers.sshhostkey = empty_fcall_info_cache; #endif ch->clone = emalloc(sizeof(uint32_t)); *ch->clone = 1; @@ -1243,13 +1162,10 @@ PHP_FUNCTION(curl_init) } /* }}} */ -static void _php_copy_callback(php_curl *ch, php_curl_callback **new_callback, php_curl_callback *source_callback, CURLoption option) +static void php_curl_copy_fcc_with_option(php_curl *ch, CURLoption option, zend_fcall_info_cache *target_fcc, zend_fcall_info_cache *source_fcc) { - if (source_callback) { - *new_callback = ecalloc(1, sizeof(php_curl_callback)); - if (!Z_ISUNDEF(source_callback->func_name)) { - ZVAL_COPY(&(*new_callback)->func_name, &source_callback->func_name); - } + if (ZEND_FCC_INITIALIZED(*source_fcc)) { + zend_fcc_dup(target_fcc, source_fcc); curl_easy_setopt(ch->cp, option, (void *) ch); } } @@ -1277,14 +1193,14 @@ 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 (ZEND_FCC_INITIALIZED(source->handlers.read->fcc)) { + zend_fcc_dup(&source->handlers.read->fcc, &source->handlers.read->fcc); } - if (!Z_ISUNDEF(source->handlers.read->func_name)) { - ZVAL_COPY(&ch->handlers.read->func_name, &source->handlers.read->func_name); + if (ZEND_FCC_INITIALIZED(source->handlers.write->fcc)) { + zend_fcc_dup(&source->handlers.write->fcc, &source->handlers.write->fcc); } - 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_header->fcc)) { + zend_fcc_dup(&source->handlers.write_header->fcc, &source->handlers.write_header->fcc); } curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str); @@ -1293,11 +1209,11 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source) curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch); curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *) ch); - _php_copy_callback(ch, &ch->handlers.progress, source->handlers.progress, CURLOPT_PROGRESSDATA); - _php_copy_callback(ch, &ch->handlers.xferinfo, source->handlers.xferinfo, CURLOPT_XFERINFODATA); - _php_copy_callback(ch, &ch->handlers.fnmatch, source->handlers.fnmatch, CURLOPT_FNMATCH_DATA); + php_curl_copy_fcc_with_option(ch, CURLOPT_PROGRESSDATA, &ch->handlers.progress, &source->handlers.progress); + php_curl_copy_fcc_with_option(ch, CURLOPT_XFERINFODATA, &ch->handlers.xferinfo, &source->handlers.xferinfo); + php_curl_copy_fcc_with_option(ch, CURLOPT_FNMATCH_DATA, &ch->handlers.fnmatch, &source->handlers.fnmatch); #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - _php_copy_callback(ch, &ch->handlers.sshhostkey, source->handlers.sshhostkey, CURLOPT_SSH_HOSTKEYDATA); + php_curl_copy_fcc_with_option(ch, CURLOPT_SSH_HOSTKEYDATA, &ch->handlers.sshhostkey, &source->handlers.sshhostkey); #endif ZVAL_COPY(&ch->private_data, &source->private_data); @@ -1598,12 +1514,64 @@ PHP_FUNCTION(curl_copy_handle) } /* }}} */ +static bool php_curl_set_callable_handler(zend_fcall_info_cache *const handler_fcc, zval *callable, bool is_array_config, const char *option_name) +{ + if (ZEND_FCC_INITIALIZED(*handler_fcc)) { + zend_fcc_dtor(handler_fcc); + } + + char *error = NULL; + if (UNEXPECTED(!zend_is_callable_ex(callable, /* object */ NULL, /* check_flags */ 0, /* callable_name */ NULL, handler_fcc, /* error */ &error))) { + if (!EG(exception)) { + zend_argument_type_error(2 + !is_array_config, "must be a valid callback for option %s, %s", option_name, error); + } + efree(error); + return false; + } + zend_fcc_addref(handler_fcc); + return true; +} + + +#define HANDLE_CURL_OPTION_CALLABLE_PHP_CURL_USER(curl_ptr, constant_no_function, handler_type) \ + case constant_no_function##FUNCTION: { \ + bool result = php_curl_set_callable_handler(&curl_ptr->handlers.handler_type->fcc, zvalue, is_array_config, #constant_no_function "FUNCTION"); \ + if (!result) { \ + return FAILURE; \ + } \ + curl_ptr->handlers.handler_type->method = PHP_CURL_USER; \ + break; \ + } + +#define HANDLE_CURL_OPTION_CALLABLE(curl_ptr, constant_no_function, handler_fcc, c_callback) \ + case constant_no_function##FUNCTION: { \ + bool result = php_curl_set_callable_handler(&curl_ptr->handler_fcc, zvalue, is_array_config, #constant_no_function "FUNCTION"); \ + if (!result) { \ + return FAILURE; \ + } \ + curl_easy_setopt(curl_ptr->cp, constant_no_function##FUNCTION, (c_callback)); \ + curl_easy_setopt(curl_ptr->cp, constant_no_function##DATA, curl_ptr); \ + break; \ + } + static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool is_array_config) /* {{{ */ { CURLcode error = CURLE_OK; zend_long lval; switch (option) { + /* Callable options */ + HANDLE_CURL_OPTION_CALLABLE_PHP_CURL_USER(ch, CURLOPT_WRITE, write); + HANDLE_CURL_OPTION_CALLABLE_PHP_CURL_USER(ch, CURLOPT_HEADER, write_header); + HANDLE_CURL_OPTION_CALLABLE_PHP_CURL_USER(ch, CURLOPT_READ, read); + + HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_PROGRESS, handlers.progress, curl_progress); + HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_XFERINFO, handlers.xferinfo, curl_xferinfo); + HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_FNMATCH_, handlers.fnmatch, curl_fnmatch); +#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ + HANDLE_CURL_OPTION_CALLABLE(ch, CURLOPT_SSH_HOSTKEY, handlers.sshhostkey, curl_ssh_hostkeyfunction); +#endif + /* Long options */ case CURLOPT_SSL_VERIFYHOST: lval = zval_get_long(zvalue); @@ -2113,15 +2081,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) { @@ -2142,41 +2101,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue } break; - case CURLOPT_PROGRESSFUNCTION: - curl_easy_setopt(ch->cp, CURLOPT_PROGRESSFUNCTION, curl_progress); - curl_easy_setopt(ch->cp, CURLOPT_PROGRESSDATA, ch); - if (ch->handlers.progress == NULL) { - ch->handlers.progress = ecalloc(1, sizeof(php_curl_callback)); - } else if (!Z_ISUNDEF(ch->handlers.progress->func_name)) { - zval_ptr_dtor(&ch->handlers.progress->func_name); - ch->handlers.progress->fci_cache = empty_fcall_info_cache; - } - ZVAL_COPY(&ch->handlers.progress->func_name, zvalue); - break; - -#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - case CURLOPT_SSH_HOSTKEYFUNCTION: - curl_easy_setopt(ch->cp, CURLOPT_SSH_HOSTKEYFUNCTION, curl_ssh_hostkeyfunction); - curl_easy_setopt(ch->cp, CURLOPT_SSH_HOSTKEYDATA, ch); - if (ch->handlers.sshhostkey == NULL) { - ch->handlers.sshhostkey = ecalloc(1, sizeof(php_curl_callback)); - } else if (!Z_ISUNDEF(ch->handlers.sshhostkey->func_name)) { - zval_ptr_dtor(&ch->handlers.sshhostkey->func_name); - ch->handlers.sshhostkey->fci_cache = empty_fcall_info_cache; - } - ZVAL_COPY(&ch->handlers.sshhostkey->func_name, zvalue); - break; -#endif - - case CURLOPT_READFUNCTION: - if (!Z_ISUNDEF(ch->handlers.read->func_name)) { - zval_ptr_dtor(&ch->handlers.read->func_name); - ch->handlers.read->fci_cache = empty_fcall_info_cache; - } - ZVAL_COPY(&ch->handlers.read->func_name, zvalue); - ch->handlers.read->method = PHP_CURL_USER; - break; - case CURLOPT_RETURNTRANSFER: if (zend_is_true(zvalue)) { ch->handlers.write->method = PHP_CURL_RETURN; @@ -2185,27 +2109,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; - - case CURLOPT_XFERINFOFUNCTION: - curl_easy_setopt(ch->cp, CURLOPT_XFERINFOFUNCTION, curl_xferinfo); - curl_easy_setopt(ch->cp, CURLOPT_XFERINFODATA, ch); - if (ch->handlers.xferinfo == NULL) { - ch->handlers.xferinfo = ecalloc(1, sizeof(php_curl_callback)); - } else if (!Z_ISUNDEF(ch->handlers.xferinfo->func_name)) { - zval_ptr_dtor(&ch->handlers.xferinfo->func_name); - ch->handlers.xferinfo->fci_cache = empty_fcall_info_cache; - } - ZVAL_COPY(&ch->handlers.xferinfo->func_name, zvalue); - break; - /* Curl off_t options */ case CURLOPT_MAX_RECV_SPEED_LARGE: case CURLOPT_MAX_SEND_SPEED_LARGE: @@ -2234,7 +2137,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue case CURLOPT_ISSUERCERT: case CURLOPT_SSH_KNOWNHOSTS: { - zend_string *tmp_str; + zend_string *tmp_str; zend_string *str = zval_get_tmp_string(zvalue, &tmp_str); zend_result ret; @@ -2275,18 +2178,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue } break; - case CURLOPT_FNMATCH_FUNCTION: - curl_easy_setopt(ch->cp, CURLOPT_FNMATCH_FUNCTION, curl_fnmatch); - curl_easy_setopt(ch->cp, CURLOPT_FNMATCH_DATA, ch); - if (ch->handlers.fnmatch == NULL) { - ch->handlers.fnmatch = ecalloc(1, sizeof(php_curl_callback)); - } else if (!Z_ISUNDEF(ch->handlers.fnmatch->func_name)) { - zval_ptr_dtor(&ch->handlers.fnmatch->func_name); - ch->handlers.fnmatch->fci_cache = empty_fcall_info_cache; - } - ZVAL_COPY(&ch->handlers.fnmatch->func_name, zvalue); - break; - /* Curl blob options */ #if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ case CURLOPT_ISSUERCERT_BLOB: @@ -2775,14 +2666,6 @@ PHP_FUNCTION(curl_close) } /* }}} */ -static void _php_curl_free_callback(php_curl_callback* callback) -{ - if (callback) { - zval_ptr_dtor(&callback->func_name); - efree(callback); - } -} - static void curl_free_obj(zend_object *object) { php_curl *ch = curl_from_obj(object); @@ -2799,20 +2682,6 @@ static void curl_free_obj(zend_object *object) _php_curl_verify_handlers(ch, /* reporterror */ false); - /* - * Libcurl is doing connection caching. When easy handle is cleaned up, - * if the handle was previously used by the curl_multi_api, the connection - * remains open un the curl multi handle is cleaned up. Some protocols are - * sending content like the FTP one, and libcurl try to use the - * WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those - * callback are freed, we need to use an other callback to which avoid - * segfaults. - * - * Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2 - */ - curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing); - curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing); - curl_easy_cleanup(ch->cp); /* cURL destructors should be invoked only by last curl handle */ @@ -2827,9 +2696,15 @@ 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); + } + if (ZEND_FCC_INITIALIZED(ch->handlers.read->fcc)) { + zend_fcc_dtor(&ch->handlers.read->fcc); + } zval_ptr_dtor(&ch->handlers.std_err); if (ch->header.str) { zend_string_release_ex(ch->header.str, 0); @@ -2843,11 +2718,19 @@ static void curl_free_obj(zend_object *object) efree(ch->handlers.write_header); efree(ch->handlers.read); - _php_curl_free_callback(ch->handlers.progress); - _php_curl_free_callback(ch->handlers.xferinfo); - _php_curl_free_callback(ch->handlers.fnmatch); + if (ZEND_FCC_INITIALIZED(ch->handlers.progress)) { + zend_fcc_dtor(&ch->handlers.progress); + } + if (ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) { + zend_fcc_dtor(&ch->handlers.xferinfo); + } + if (ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) { + zend_fcc_dtor(&ch->handlers.fnmatch); + } #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - _php_curl_free_callback(ch->handlers.sshhostkey); + if (ZEND_FCC_INITIALIZED(ch->handlers.sshhostkey)) { + zend_fcc_dtor(&ch->handlers.sshhostkey); + } #endif zval_ptr_dtor(&ch->postfields); @@ -2911,29 +2794,21 @@ static void _php_curl_reset_handlers(php_curl *ch) ZVAL_UNDEF(&ch->handlers.std_err); } - if (ch->handlers.progress) { - zval_ptr_dtor(&ch->handlers.progress->func_name); - efree(ch->handlers.progress); - ch->handlers.progress = NULL; + if (ZEND_FCC_INITIALIZED(ch->handlers.progress)) { + zend_fcc_dtor(&ch->handlers.progress); } - if (ch->handlers.xferinfo) { - zval_ptr_dtor(&ch->handlers.xferinfo->func_name); - efree(ch->handlers.xferinfo); - ch->handlers.xferinfo = NULL; + if (ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) { + zend_fcc_dtor(&ch->handlers.xferinfo); } - if (ch->handlers.fnmatch) { - zval_ptr_dtor(&ch->handlers.fnmatch->func_name); - efree(ch->handlers.fnmatch); - ch->handlers.fnmatch = NULL; + if (ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) { + zend_fcc_dtor(&ch->handlers.fnmatch); } #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ - if (ch->handlers.sshhostkey) { - zval_ptr_dtor(&ch->handlers.sshhostkey->func_name); - efree(ch->handlers.sshhostkey); - ch->handlers.sshhostkey = NULL; + if (ZEND_FCC_INITIALIZED(ch->handlers.sshhostkey)) { + zend_fcc_dtor(&ch->handlers.sshhostkey); } #endif } diff --git a/ext/curl/multi.c b/ext/curl/multi.c index a61066b5a6c7c..586f48911b261 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -372,51 +372,35 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea php_curl *parent; php_curlm *mh = (php_curlm *)userp; size_t rval = CURL_PUSH_DENY; - php_curl_callback *t = mh->handlers.server_push; zval *pz_parent_ch = NULL; zval pz_ch; zval headers; zval retval; - char *header; - zend_result error; - zend_fcall_info fci = empty_fcall_info; pz_parent_ch = _php_curl_multi_find_easy_handle(mh, parent_ch); if (pz_parent_ch == NULL) { return rval; } - if (UNEXPECTED(zend_fcall_info_init(&t->func_name, 0, &fci, &t->fci_cache, NULL, NULL) == FAILURE)) { - php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION"); - return rval; - } - parent = Z_CURL_P(pz_parent_ch); ch = init_curl_handle_into_zval(&pz_ch); ch->cp = easy; _php_setup_easy_copy_handlers(ch, parent); - size_t i; array_init(&headers); - for(i=0; ifci_cache); + zend_call_known_fcc(&mh->handlers.server_push, &retval, /* param_count */ 3, call_args, /* named_params */ NULL); zval_ptr_dtor_nogc(&headers); - if (error == FAILURE) { - php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION"); - } else if (!Z_ISUNDEF(retval)) { + if (!Z_ISUNDEF(retval)) { if (CURL_PUSH_DENY != zval_get_long(&retval)) { rval = CURL_PUSH_OK; zend_llist_add_element(&mh->easyh, &pz_ch); @@ -458,21 +442,29 @@ static bool _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue error = curl_multi_setopt(mh->multi, option, lval); break; } - case CURLMOPT_PUSHFUNCTION: - if (mh->handlers.server_push == NULL) { - mh->handlers.server_push = ecalloc(1, sizeof(php_curl_callback)); - } else if (!Z_ISUNDEF(mh->handlers.server_push->func_name)) { - zval_ptr_dtor(&mh->handlers.server_push->func_name); - mh->handlers.server_push->fci_cache = empty_fcall_info_cache; + case CURLMOPT_PUSHFUNCTION: { + /* See php_curl_set_callable_handler */ + if (ZEND_FCC_INITIALIZED(mh->handlers.server_push)) { + zend_fcc_dtor(&mh->handlers.server_push); } - ZVAL_COPY(&mh->handlers.server_push->func_name, zvalue); + char *error_str = NULL; + if (UNEXPECTED(!zend_is_callable_ex(zvalue, /* object */ NULL, /* check_flags */ 0, /* callable_name */ NULL, &mh->handlers.server_push, /* error */ &error_str))) { + if (!EG(exception)) { + zend_argument_type_error(2, "must be a valid callback for option CURLMOPT_PUSHFUNCTION, %s", error_str); + } + efree(error_str); + return false; + } + zend_fcc_addref(&mh->handlers.server_push); + error = curl_multi_setopt(mh->multi, CURLMOPT_PUSHFUNCTION, _php_server_push_callback); if (error != CURLM_OK) { return false; } error = curl_multi_setopt(mh->multi, CURLMOPT_PUSHDATA, mh); break; + } default: zend_argument_value_error(2, "is not a valid cURL multi option"); error = CURLM_UNKNOWN_OPTION; @@ -548,9 +540,9 @@ static void curl_multi_free_obj(zend_object *object) 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 (ZEND_FCC_INITIALIZED(mh->handlers.server_push)) { + zend_fcc_dtor(&mh->handlers.server_push); } zend_object_std_dtor(&mh->std); @@ -562,8 +554,8 @@ static HashTable *curl_multi_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); - if (curl_multi->handlers.server_push) { - zend_get_gc_buffer_add_zval(gc_buffer, &curl_multi->handlers.server_push->func_name); + if (ZEND_FCC_INITIALIZED(curl_multi->handlers.server_push)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &curl_multi->handlers.server_push); } zend_llist_position pos; diff --git a/ext/curl/tests/curl_copy_handle_basic_008.phpt b/ext/curl/tests/curl_copy_handle_basic_008.phpt deleted file mode 100644 index c1ab325660cf8..0000000000000 --- a/ext/curl/tests/curl_copy_handle_basic_008.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -Test curl_copy_handle() with CURLOPT_PROGRESSFUNCTION ---EXTENSIONS-- -curl ---FILE-- - ---EXPECT-- -Hello World! -Hello World! -Hello World! -Hello World! diff --git a/ext/curl/tests/curl_copy_handle_xferinfo.phpt b/ext/curl/tests/curl_copy_handle_xferinfo.phpt index 55050551b797e..bf9c1f43beea0 100644 --- a/ext/curl/tests/curl_copy_handle_xferinfo.phpt +++ b/ext/curl/tests/curl_copy_handle_xferinfo.phpt @@ -4,19 +4,23 @@ Test curl_copy_handle() with CURLOPT_XFERINFOFUNCTION curl --FILE-- --EXPECT-- diff --git a/ext/curl/tests/curl_fnmatch_trampoline.phpt b/ext/curl/tests/curl_fnmatch_trampoline.phpt new file mode 100644 index 0000000000000..ffc286cae8846 --- /dev/null +++ b/ext/curl/tests/curl_fnmatch_trampoline.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test trampoline for curl option CURLOPT_FNMATCH_FUNCTION +--EXTENSIONS-- +curl +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Trampoline for trampoline +Hello World! +Hello World! diff --git a/ext/curl/tests/curl_multi_setopt_callables.phpt b/ext/curl/tests/curl_multi_setopt_callables.phpt new file mode 100644 index 0000000000000..c0de5add49101 --- /dev/null +++ b/ext/curl/tests/curl_multi_setopt_callables.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test curl_multi_setopt() with options that take callabes +--EXTENSIONS-- +curl +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +TypeError: curl_multi_setopt(): Argument #2 ($option) must be a valid callback for option CURLMOPT_PUSHFUNCTION, function "undefined" not found or invalid function name diff --git a/ext/curl/tests/curl_progress.phpt b/ext/curl/tests/curl_progress.phpt new file mode 100644 index 0000000000000..5a7e488812233 --- /dev/null +++ b/ext/curl/tests/curl_progress.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test curl_copy_handle() with CURLOPT_PROGRESSFUNCTION +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +Hello World! +Hello World! +Hello World! +Hello World! diff --git a/ext/curl/tests/curl_progress_trampoline.phpt b/ext/curl/tests/curl_progress_trampoline.phpt new file mode 100644 index 0000000000000..d3d31e6aec891 --- /dev/null +++ b/ext/curl/tests/curl_progress_trampoline.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test trampoline for curl option CURLOPT_PROGRESSFUNCTION +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +Trampoline for trampoline +Hello World! +Hello World! diff --git a/ext/curl/tests/curl_pushfunction_nonexistent_callback.phpt b/ext/curl/tests/curl_pushfunction_trampoline.phpt similarity index 62% rename from ext/curl/tests/curl_pushfunction_nonexistent_callback.phpt rename to ext/curl/tests/curl_pushfunction_trampoline.phpt index fe2defa5eea08..de6da63914045 100644 --- a/ext/curl/tests/curl_pushfunction_nonexistent_callback.phpt +++ b/ext/curl/tests/curl_pushfunction_trampoline.phpt @@ -1,9 +1,5 @@ --TEST-- -Test CURLMOPT_PUSHFUNCTION with non-existent callback function ---CREDITS-- -Davey Shafik -Kévin Dunglas -Niels Dossche +Test trampoline for curl option CURLMOPT_PUSHFUNCTION --EXTENSIONS-- curl --SKIPIF-- @@ -17,12 +13,20 @@ if ($curl_version['version_number'] < 0x080100) { ?> --FILE-- ---EXPECTF-- -Warning: curl_multi_exec(): Cannot call the CURLMOPT_PUSHFUNCTION in %s on line %d +--EXPECT-- +Array +( + [0] => main response + [1] => pushed response +) diff --git a/ext/curl/tests/curl_setopt_CURLOPT_READFUNCTION.phpt b/ext/curl/tests/curl_read_callback.phpt similarity index 100% rename from ext/curl/tests/curl_setopt_CURLOPT_READFUNCTION.phpt rename to ext/curl/tests/curl_read_callback.phpt diff --git a/ext/curl/tests/curl_read_trampoline.phpt b/ext/curl/tests/curl_read_trampoline.phpt new file mode 100644 index 0000000000000..f69caebf79875 --- /dev/null +++ b/ext/curl/tests/curl_read_trampoline.phpt @@ -0,0 +1,49 @@ +--TEST-- +Test trampoline for curl option CURLOPT_READFUNCTION +--EXTENSIONS-- +curl +--FILE-- + +--CLEAN-- + +--EXPECT-- +Trampoline for trampoline +string(0) "" diff --git a/ext/curl/tests/curl_setopt_callables.phpt b/ext/curl/tests/curl_setopt_callables.phpt new file mode 100644 index 0000000000000..6cde8fef6d9c7 --- /dev/null +++ b/ext/curl/tests/curl_setopt_callables.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test curl_setopt(_array)() with options that take callabes +--EXTENSIONS-- +curl +--FILE-- +getMessage(), PHP_EOL; + } + + try { + var_dump(curl_setopt_array($handle, [$option => 'undefined'])); + } catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; + } +} + +$url = "https://example.com"; +$ch = curl_init($url); +testOption($ch, CURLOPT_PROGRESSFUNCTION); +testOption($ch, CURLOPT_XFERINFOFUNCTION); +testOption($ch, CURLOPT_FNMATCH_FUNCTION); +testOption($ch, CURLOPT_WRITEFUNCTION); +testOption($ch, CURLOPT_HEADERFUNCTION); +testOption($ch, CURLOPT_READFUNCTION); + +?> +--EXPECT-- +TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_PROGRESSFUNCTION, function "undefined" not found or invalid function name +TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_PROGRESSFUNCTION, function "undefined" not found or invalid function name +TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_XFERINFOFUNCTION, function "undefined" not found or invalid function name +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 +TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_READFUNCTION, function "undefined" not found or invalid function name +TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_READFUNCTION, function "undefined" not found or invalid function name diff --git a/ext/curl/tests/curl_ssh_hostkey_invalid_callable.phpt b/ext/curl/tests/curl_ssh_hostkey_invalid_callable.phpt new file mode 100644 index 0000000000000..f17fae9cbaa2d --- /dev/null +++ b/ext/curl/tests/curl_ssh_hostkey_invalid_callable.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test curl_setopt(_array)() with CURLOPT_SSH_HOSTKEYFUNCTION option +--EXTENSIONS-- +curl +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; + } + + try { + var_dump(curl_setopt_array($handle, [$option => 'undefined'])); + } catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; + } +} + +$url = "https://example.com"; +$ch = curl_init($url); +testOption($ch, CURLOPT_SSH_HOSTKEYFUNCTION); + +?> +--EXPECT-- +TypeError: curl_setopt(): Argument #3 ($value) must be a valid callback for option CURLOPT_SSH_HOSTKEYFUNCTION, function "undefined" not found or invalid function name +TypeError: curl_setopt_array(): Argument #2 ($options) must be a valid callback for option CURLOPT_SSH_HOSTKEYFUNCTION, function "undefined" not found or invalid function name diff --git a/ext/curl/tests/curl_ssh_hostkey_trampoline.phpt b/ext/curl/tests/curl_ssh_hostkey_trampoline.phpt new file mode 100644 index 0000000000000..84ce8eb85115a --- /dev/null +++ b/ext/curl/tests/curl_ssh_hostkey_trampoline.phpt @@ -0,0 +1,41 @@ +--TEST-- +Test trampoline for curl option CURLOPT_SSH_HOSTKEYFUNCTION +--EXTENSIONS-- +curl +--SKIPIF-- += 7.84.0"); +} +exit("skip: cannot properly test CURLOPT_SSH_HOSTKEYFUNCTION"); +?> +--FILE-- + +--EXPECT-- +Trampoline for trampoline +FAKE diff --git a/ext/curl/tests/curl_write_trampoline.phpt b/ext/curl/tests/curl_write_trampoline.phpt new file mode 100644 index 0000000000000..8d604bc7bd4fc --- /dev/null +++ b/ext/curl/tests/curl_write_trampoline.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test trampoline for curl option CURLOPT_WRITEFUNCTION +--EXTENSIONS-- +curl +--FILE-- + +--CLEAN-- + +--EXPECT-- +Trampoline for trampoline diff --git a/ext/curl/tests/curl_writeheader_tranpoline.phpt b/ext/curl/tests/curl_writeheader_tranpoline.phpt new file mode 100644 index 0000000000000..48c53f3996a44 --- /dev/null +++ b/ext/curl/tests/curl_writeheader_tranpoline.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test trampoline for curl option CURLOPT_HEADERFUNCTION +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +Trampoline for trampoline diff --git a/ext/curl/tests/curl_xferinfo_trampoline.phpt b/ext/curl/tests/curl_xferinfo_trampoline.phpt new file mode 100644 index 0000000000000..f10ea890dcba8 --- /dev/null +++ b/ext/curl/tests/curl_xferinfo_trampoline.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test trampoline for curl option CURLOPT_XFERINFOFUNCTION +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +Trampoline for trampoline +Hello World! +Hello World!