mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
ext/curl: Refactor cURL to only use FCC (#13291)
* ext/curl: Convert handlers.progress to just be a FCC * ext/curl: Convert handlers.sshhostkey to just be a FCC * ext/curl: Convert handlers.xferinfo to just be a FCC * ext/curl: Convert handlers.fnmatch to just be a FCC * ext/curl: Convert handlers.server_push to just be a FCC * ext/curl: Convert php_curl_write to just use FCC without a function name zval * ext/curl: Convert php_curl_read to just use FCC without a function name zval * ext/curl: Remove workaround for old libcurl * ext/curl: Create macros to codegen the handling of callable options
This commit is contained in:
committed by
GitHub
parent
0540a4211d
commit
f4dbe2390d
@@ -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 {
|
||||
|
||||
@@ -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 = true;
|
||||
zend_call_known_fcc(&ch->handlers.fnmatch, &retval, /* param_count */ 3, argv, /* named_params */ NULL);
|
||||
ch->in_callback = false;
|
||||
|
||||
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)) {
|
||||
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);
|
||||
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);
|
||||
|
||||
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 = true;
|
||||
zend_call_known_fcc(&ch->handlers.progress, &retval, /* param_count */ 5, args, /* named_params */ NULL);
|
||||
ch->in_callback = false;
|
||||
|
||||
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)) {
|
||||
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 = true;
|
||||
zend_call_known_fcc(&ch->handlers.xferinfo, &retval, /* param_count */ 5, argv, /* named_params */ NULL);
|
||||
ch->in_callback = false;
|
||||
|
||||
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)) {
|
||||
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);
|
||||
ZVAL_OBJ(&args[0], &ch->std);
|
||||
ZVAL_LONG(&args[1], keytype);
|
||||
ZVAL_STRINGL(&args[2], key, keylen);
|
||||
ZVAL_LONG(&args[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 = true;
|
||||
zend_call_known_fcc(&ch->handlers.sshhostkey, &retval, /* param_count */ 4, args, /* named_params */ NULL);
|
||||
ch->in_callback = false;
|
||||
|
||||
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)) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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; i<num_headers; i++) {
|
||||
header = curl_pushheader_bynum(push_headers, i);
|
||||
for (size_t i = 0; i < num_headers; i++) {
|
||||
char *header = curl_pushheader_bynum(push_headers, i);
|
||||
add_next_index_string(&headers, header);
|
||||
}
|
||||
|
||||
ZEND_ASSERT(pz_parent_ch);
|
||||
zval call_args[3] = {*pz_parent_ch, pz_ch, headers};
|
||||
|
||||
fci.param_count = 3;
|
||||
fci.params = call_args;
|
||||
fci.retval = &retval;
|
||||
|
||||
error = zend_call_function(&fci, &t->fci_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;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
--TEST--
|
||||
Test curl_copy_handle() with CURLOPT_PROGRESSFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function() { });
|
||||
$ch2 = curl_copy_handle($ch);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
unset($ch);
|
||||
echo curl_exec($ch2);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Hello World!
|
||||
Hello World!
|
||||
Hello World!
|
||||
Hello World!
|
||||
@@ -4,19 +4,23 @@ Test curl_copy_handle() with CURLOPT_XFERINFOFUNCTION
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, function() { static $done = false; if (!$done) { echo "Download progress!\n"; $done = true; } });
|
||||
$ch2 = curl_copy_handle($ch);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
unset($ch);
|
||||
echo curl_exec($ch2);
|
||||
function foo() {
|
||||
static $done = false; if (!$done) { echo "Download progress!\n"; $done = true; }
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, 'foo');
|
||||
$ch2 = curl_copy_handle($ch);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
unset($ch);
|
||||
echo curl_exec($ch2);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
|
||||
34
ext/curl/tests/curl_fnmatch_trampoline.phpt
Normal file
34
ext/curl/tests/curl_fnmatch_trampoline.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_FNMATCH_FUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
exit("skip: cannot properly test CURLOPT_FNMATCH_FUNCTION");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
return CURL_FNMATCHFUNC_NOMATCH;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
$url = "ftp://{$host}/file*";
|
||||
//$url = "ftp://ftp.example.com/file*";
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_WILDCARDMATCH, 1);
|
||||
curl_setopt($ch, CURLOPT_FNMATCH_FUNCTION, $callback);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
Hello World!
|
||||
Hello World!
|
||||
17
ext/curl/tests/curl_multi_setopt_callables.phpt
Normal file
17
ext/curl/tests/curl_multi_setopt_callables.phpt
Normal file
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Test curl_multi_setopt() with options that take callabes
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$mh = curl_multi_init();
|
||||
try {
|
||||
var_dump(curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, 'undefined'));
|
||||
} catch (Throwable $e) {
|
||||
echo $e::class, ': ', $e->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
|
||||
25
ext/curl/tests/curl_progress.phpt
Normal file
25
ext/curl/tests/curl_progress.phpt
Normal file
@@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Test curl_copy_handle() with CURLOPT_PROGRESSFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function() { });
|
||||
$ch2 = curl_copy_handle($ch);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
unset($ch);
|
||||
echo curl_exec($ch2);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Hello World!
|
||||
Hello World!
|
||||
Hello World!
|
||||
Hello World!
|
||||
34
ext/curl/tests/curl_progress_trampoline.phpt
Normal file
34
ext/curl/tests/curl_progress_trampoline.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_PROGRESSFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
static $done = false;
|
||||
if (!$done) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
$done = true;
|
||||
}
|
||||
return CURL_PUSH_OK;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, $callback);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
Hello World!
|
||||
Hello World!
|
||||
@@ -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--
|
||||
<?php
|
||||
// Test adapted from curl_pushfunction.phpt
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
return CURL_PUSH_OK;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
$mh = curl_multi_init();
|
||||
|
||||
curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
|
||||
curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, "nonexistent");
|
||||
curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $callback);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, "https://localhost/serverpush");
|
||||
@@ -31,8 +35,9 @@ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
curl_multi_add_handle($mh, $ch);
|
||||
|
||||
$responses = [];
|
||||
$active = null;
|
||||
while(true) {
|
||||
do {
|
||||
$status = curl_multi_exec($mh, $active);
|
||||
|
||||
do {
|
||||
@@ -40,15 +45,22 @@ while(true) {
|
||||
if (false !== $info && $info['msg'] == CURLMSG_DONE) {
|
||||
$handle = $info['handle'];
|
||||
if ($handle !== null) {
|
||||
$responses[] = curl_multi_getcontent($info['handle']);
|
||||
curl_multi_remove_handle($mh, $handle);
|
||||
curl_close($handle);
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
} while ($info);
|
||||
}
|
||||
} while (count($responses) !== 2);
|
||||
|
||||
curl_multi_close($mh);
|
||||
|
||||
sort($responses);
|
||||
print_r($responses);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: curl_multi_exec(): Cannot call the CURLMOPT_PUSHFUNCTION in %s on line %d
|
||||
--EXPECT--
|
||||
Array
|
||||
(
|
||||
[0] => main response
|
||||
[1] => pushed response
|
||||
)
|
||||
49
ext/curl/tests/curl_read_trampoline.phpt
Normal file
49
ext/curl/tests/curl_read_trampoline.phpt
Normal file
@@ -0,0 +1,49 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_READFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
$sFileBase = __DIR__.DIRECTORY_SEPARATOR.'curl_read_trampoline';
|
||||
$sReadFile = $sFileBase.'_in.tmp';
|
||||
$sWriteFile = $sFileBase.'_out.tmp';
|
||||
$sWriteUrl = 'file://'.$sWriteFile;
|
||||
|
||||
file_put_contents($sReadFile,'contents of tempfile');
|
||||
$hReadHandle = fopen($sReadFile, 'r');
|
||||
|
||||
$oCurl = curl_init();
|
||||
curl_setopt($oCurl, CURLOPT_URL, $sWriteUrl);
|
||||
curl_setopt($oCurl, CURLOPT_UPLOAD, 1);
|
||||
curl_setopt($oCurl, CURLOPT_READFUNCTION, $callback);
|
||||
curl_setopt($oCurl, CURLOPT_INFILE, $hReadHandle );
|
||||
curl_exec($oCurl);
|
||||
curl_close($oCurl);
|
||||
|
||||
fclose ($hReadHandle);
|
||||
|
||||
$sOutput = file_get_contents($sWriteFile);
|
||||
var_dump($sOutput);
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$sFileBase = __DIR__.DIRECTORY_SEPARATOR.'curl_read_trampoline';
|
||||
$sReadFile = $sFileBase.'_in.tmp';
|
||||
$sWriteFile = $sFileBase.'_out.tmp';
|
||||
@unlink($sReadFile);
|
||||
@unlink($sWriteFile);
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
string(0) ""
|
||||
44
ext/curl/tests/curl_setopt_callables.phpt
Normal file
44
ext/curl/tests/curl_setopt_callables.phpt
Normal file
@@ -0,0 +1,44 @@
|
||||
--TEST--
|
||||
Test curl_setopt(_array)() with options that take callabes
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function testOption(CurlHandle $handle, int $option) {
|
||||
try {
|
||||
var_dump(curl_setopt($handle, $option, 'undefined'));
|
||||
} catch (Throwable $e) {
|
||||
echo $e::class, ': ', $e->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
|
||||
36
ext/curl/tests/curl_ssh_hostkey_invalid_callable.phpt
Normal file
36
ext/curl/tests/curl_ssh_hostkey_invalid_callable.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Test curl_setopt(_array)() with CURLOPT_SSH_HOSTKEYFUNCTION option
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
$curl_version = curl_version();
|
||||
if ($curl_version['version_number'] < 0x075400) {
|
||||
die("skip: blob options not supported for curl < 7.84.0");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function testOption(CurlHandle $handle, int $option) {
|
||||
try {
|
||||
var_dump(curl_setopt($handle, $option, 'undefined'));
|
||||
} catch (Throwable $e) {
|
||||
echo $e::class, ': ', $e->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
|
||||
41
ext/curl/tests/curl_ssh_hostkey_trampoline.phpt
Normal file
41
ext/curl/tests/curl_ssh_hostkey_trampoline.phpt
Normal file
@@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_SSH_HOSTKEYFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
$curl_version = curl_version();
|
||||
if ($curl_version['version_number'] < 0x075400) {
|
||||
exit("skip: test works only with curl >= 7.84.0");
|
||||
}
|
||||
exit("skip: cannot properly test CURLOPT_SSH_HOSTKEYFUNCTION");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
return CURLKHMATCH_MISMATCH;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
include 'server.inc';
|
||||
$ch = curl_init();
|
||||
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
var_dump($host);
|
||||
//$url = "scp://{$host}/get.inc";
|
||||
//$url = "scp://example.com/example.txt";
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
var_dump(curl_setopt($ch, CURLOPT_SSH_HOSTKEYFUNCTION, $callback));
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
FAKE
|
||||
36
ext/curl/tests/curl_write_trampoline.phpt
Normal file
36
ext/curl/tests/curl_write_trampoline.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_WRITEFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
$log_file = tempnam(sys_get_temp_dir(), 'php-curl-CURLOPT_WRITEFUNCTION-trampoline');
|
||||
|
||||
$fp = fopen($log_file, 'w+');
|
||||
fwrite($fp, "test");
|
||||
fclose($fp);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $callback);
|
||||
curl_setopt($ch, CURLOPT_URL, 'file://' . $log_file);
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$log_file = tempnam(sys_get_temp_dir(), 'php-curl-CURLOPT_WRITEFUNCTION-trampoline');
|
||||
@unlink($log_file);
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
28
ext/curl/tests/curl_writeheader_tranpoline.phpt
Normal file
28
ext/curl/tests/curl_writeheader_tranpoline.phpt
Normal file
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_HEADERFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
return CURL_PUSH_OK;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HEADERFUNCTION, $callback);
|
||||
curl_setopt($ch, CURLOPT_URL, $host);
|
||||
curl_exec($ch);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
34
ext/curl/tests/curl_xferinfo_trampoline.phpt
Normal file
34
ext/curl/tests/curl_xferinfo_trampoline.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
Test trampoline for curl option CURLOPT_XFERINFOFUNCTION
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments) {
|
||||
static $done = false;
|
||||
if (!$done) {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
$done = true;
|
||||
}
|
||||
return CURL_PUSH_OK;
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, $callback);
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Trampoline for trampoline
|
||||
Hello World!
|
||||
Hello World!
|
||||
Reference in New Issue
Block a user