diff options
-rw-r--r-- | ext/curl/interface.c | 160 | ||||
-rw-r--r-- | ext/curl/php_curl.h | 3 | ||||
-rw-r--r-- | ext/curl/tests/bug27023.phpt | 8 | ||||
-rw-r--r-- | ext/curl/tests/bug77711.phpt | 2 | ||||
-rw-r--r-- | ext/curl/tests/curl_copy_handle_variation3.phpt | 4 | ||||
-rw-r--r-- | ext/curl/tests/curl_copy_handle_variation4.phpt | 46 | ||||
-rw-r--r-- | ext/curl/tests/curl_copy_handle_variation5.phpt | 52 | ||||
-rw-r--r-- | ext/curl/tests/curl_file_upload.phpt | 12 | ||||
-rw-r--r-- | ext/curl/tests/curl_file_upload_stream.phpt | 2 | ||||
-rw-r--r-- | ext/curl/tests/responder/get.inc | 2 |
10 files changed, 221 insertions, 70 deletions
diff --git a/ext/curl/interface.c b/ext/curl/interface.c index a8d6602572..23732dcfcb 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1591,11 +1591,20 @@ static void curl_free_post(void **post) } /* }}} */ -/* {{{ curl_free_stream +struct mime_data_cb_arg { + zend_string *filename; + php_stream *stream; +}; + +/* {{{ curl_free_cb_arg */ -static void curl_free_stream(void **post) +static void curl_free_cb_arg(void **cb_arg_p) { - php_stream_close((php_stream *)*post); + struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) *cb_arg_p; + + ZEND_ASSERT(cb_arg->stream == NULL); + zend_string_release(cb_arg->filename); + efree(cb_arg); } /* }}} */ @@ -1692,11 +1701,13 @@ php_curl *alloc_curl_handle() zend_llist_init(&ch->to_free->str, sizeof(char *), (llist_dtor_func_t)curl_free_string, 0); zend_llist_init(&ch->to_free->post, sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post, 0); - zend_llist_init(&ch->to_free->stream, sizeof(php_stream *), (llist_dtor_func_t)curl_free_stream, 0); + zend_llist_init(&ch->to_free->stream, sizeof(struct mime_data_cb_arg *), (llist_dtor_func_t)curl_free_cb_arg, 0); ch->to_free->slist = emalloc(sizeof(HashTable)); zend_hash_init(ch->to_free->slist, 4, NULL, curl_free_slist, 0); - +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ + ZVAL_UNDEF(&ch->postfields); +#endif return ch; } /* }}} */ @@ -1882,62 +1893,48 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source) (*source->clone)++; } -/* {{{ proto resource curl_copy_handle(resource ch) - Copy a cURL handle along with all of it's preferences */ -PHP_FUNCTION(curl_copy_handle) +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ +static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */ { - CURL *cp; - zval *zid; - php_curl *ch, *dupch; - - ZEND_PARSE_PARAMETERS_START(1,1) - Z_PARAM_RESOURCE(zid) - ZEND_PARSE_PARAMETERS_END(); + struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg; + ssize_t numread; - if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) { - RETURN_THROWS(); + if (cb_arg->stream == NULL) { + if (!(cb_arg->stream = php_stream_open_wrapper(ZSTR_VAL(cb_arg->filename), "rb", IGNORE_PATH, NULL))) { + return CURL_READFUNC_ABORT; + } } - - cp = curl_easy_duphandle(ch->cp); - if (!cp) { - php_error_docref(NULL, E_WARNING, "Cannot duplicate cURL handle"); - RETURN_FALSE; + numread = php_stream_read(cb_arg->stream, buffer, nitems * size); + if (numread < 0) { + php_stream_close(cb_arg->stream); + cb_arg->stream = NULL; + return CURL_READFUNC_ABORT; } - - dupch = alloc_curl_handle(); - dupch->cp = cp; - - _php_setup_easy_copy_handlers(dupch, ch); - - Z_ADDREF_P(zid); - - ZVAL_RES(return_value, zend_register_resource(dupch, le_curl)); - dupch->res = Z_RES_P(return_value); + return numread; } /* }}} */ -#if LIBCURL_VERSION_NUM >= 0x073800 -static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */ +static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */ { - php_stream *stream = (php_stream *) arg; - ssize_t numread = php_stream_read(stream, buffer, nitems * size); + struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg; + int res; - if (numread < 0) { - return CURL_READFUNC_ABORT; + if (cb_arg->stream == NULL) { + return CURL_SEEKFUNC_CANTSEEK; } - return numread; + res = php_stream_seek(cb_arg->stream, offset, origin); + return res == SUCCESS ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK; } /* }}} */ -static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */ +static void free_cb(void *arg) /* {{{ */ { - php_stream *stream = (php_stream *) arg; - int res = php_stream_seek(stream, offset, origin); + struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg; - if (res) { - return CURL_SEEKFUNC_CANTSEEK; + if (cb_arg->stream != NULL) { + php_stream_close(cb_arg->stream); + cb_arg->stream = NULL; } - return CURL_SEEKFUNC_OK; } /* }}} */ #endif @@ -1948,7 +1945,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields zval *current; HashTable *postfields; zend_string *string_key; - zend_ulong num_key; + zend_ulong num_key; #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ curl_mime *mime = NULL; curl_mimepart *part; @@ -1990,7 +1987,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields zval *prop, rv; char *type = NULL, *filename = NULL; #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ - php_stream *stream; + struct mime_data_cb_arg *cb_arg; #endif prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv); @@ -2013,24 +2010,25 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields } #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ - if (!(stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", IGNORE_PATH, NULL))) { - zend_string_release_ex(string_key, 0); - return FAILURE; - } + zval_ptr_dtor(&ch->postfields); + ZVAL_COPY(&ch->postfields, zpostfields); + + cb_arg = emalloc(sizeof *cb_arg); + cb_arg->filename = zend_string_copy(postval); + cb_arg->stream = NULL; + part = curl_mime_addpart(mime); if (part == NULL) { - php_stream_close(stream); zend_string_release_ex(string_key, 0); return FAILURE; } if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK - || (form_error = curl_mime_data_cb(part, -1, read_cb, seek_cb, NULL, stream)) != CURLE_OK + || (form_error = curl_mime_data_cb(part, -1, read_cb, seek_cb, free_cb, cb_arg)) != CURLE_OK || (form_error = curl_mime_filename(part, filename ? filename : ZSTR_VAL(postval))) != CURLE_OK || (form_error = curl_mime_type(part, type ? type : "application/octet-stream")) != CURLE_OK) { - php_stream_close(stream); error = form_error; } - zend_llist_add_element(&ch->to_free->stream, &stream); + zend_llist_add_element(&ch->to_free->stream, &cb_arg); #else form_error = curl_formadd(&first, &last, CURLFORM_COPYNAME, ZSTR_VAL(string_key), @@ -2098,11 +2096,60 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields zend_llist_add_element(&ch->to_free->post, &first); error = curl_easy_setopt(ch->cp, CURLOPT_HTTPPOST, first); #endif + SAVE_CURL_ERROR(ch, error); return error == CURLE_OK ? SUCCESS : FAILURE; } /* }}} */ +/* {{{ proto resource curl_copy_handle(resource ch) + Copy a cURL handle along with all of it's preferences */ +PHP_FUNCTION(curl_copy_handle) +{ + CURL *cp; + zval *zid; + php_curl *ch, *dupch; +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ + zval *postfields; +#endif + + ZEND_PARSE_PARAMETERS_START(1,1) + Z_PARAM_RESOURCE(zid) + ZEND_PARSE_PARAMETERS_END(); + + if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) { + RETURN_FALSE; + } + + cp = curl_easy_duphandle(ch->cp); + if (!cp) { + php_error_docref(NULL, E_WARNING, "Cannot duplicate cURL handle"); + RETURN_FALSE; + } + + dupch = alloc_curl_handle(); + dupch->cp = cp; + + _php_setup_easy_copy_handlers(dupch, ch); + +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ + postfields = &ch->postfields; + if (Z_TYPE_P(postfields) != IS_UNDEF) { + if (build_mime_structure_from_hash(dupch, postfields) != SUCCESS) { + _php_curl_close_ex(dupch); + php_error_docref(NULL, E_WARNING, "Cannot rebuild mime structure"); + RETURN_FALSE; + } + } +#endif + + Z_ADDREF_P(zid); + + ZVAL_RES(return_value, zend_register_resource(dupch, le_curl)); + dupch->res = Z_RES_P(return_value); +} +/* }}} */ + static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ */ { CURLcode error = CURLE_OK; @@ -3286,6 +3333,9 @@ static void _php_curl_close_ex(php_curl *ch) } efree(ch->handlers); +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ + zval_ptr_dtor(&ch->postfields); +#endif efree(ch); } /* }}} */ diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h index 44a86bff8b..ec74e96956 100644 --- a/ext/curl/php_curl.h +++ b/ext/curl/php_curl.h @@ -181,6 +181,9 @@ typedef struct { struct _php_curl_error err; zend_bool in_callback; uint32_t* clone; +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ + zval postfields; +#endif } php_curl; #define CURLOPT_SAFE_UPLOAD -1 diff --git a/ext/curl/tests/bug27023.phpt b/ext/curl/tests/bug27023.phpt index 3d649b3f73..f985c192b8 100644 --- a/ext/curl/tests/bug27023.phpt +++ b/ext/curl/tests/bug27023.phpt @@ -38,7 +38,7 @@ var_dump(curl_exec($ch)); curl_close($ch); ?> --EXPECTF-- -string(%d) "curl_testdata1.txt|application/octet-stream" -string(%d) "curl_testdata1.txt|text/plain" -string(%d) "foo.txt|application/octet-stream" -string(%d) "foo.txt|text/plain" +string(%d) "curl_testdata1.txt|application/octet-stream|6" +string(%d) "curl_testdata1.txt|text/plain|6" +string(%d) "foo.txt|application/octet-stream|6" +string(%d) "foo.txt|text/plain|6" diff --git a/ext/curl/tests/bug77711.phpt b/ext/curl/tests/bug77711.phpt index 5845f202ba..dec53d0acb 100644 --- a/ext/curl/tests/bug77711.phpt +++ b/ext/curl/tests/bug77711.phpt @@ -23,7 +23,7 @@ curl_close($ch); ?> --EXPECTF-- bool(true) -string(%d) "АБВ.txt|application/octet-stream" +string(%d) "АБВ.txt|application/octet-stream|5" --CLEAN-- <?php @unlink(__DIR__ . '/АБВ.txt'); diff --git a/ext/curl/tests/curl_copy_handle_variation3.phpt b/ext/curl/tests/curl_copy_handle_variation3.phpt index 9a94df8d10..ae643f4b30 100644 --- a/ext/curl/tests/curl_copy_handle_variation3.phpt +++ b/ext/curl/tests/curl_copy_handle_variation3.phpt @@ -28,8 +28,8 @@ curl_close($ch2); ?> --EXPECTF-- bool(true) -string(%d) "АБВ.txt|application/octet-stream" -string(%d) "АБВ.txt|application/octet-stream" +string(%d) "АБВ.txt|application/octet-stream|5" +string(%d) "АБВ.txt|application/octet-stream|5" --CLEAN-- <?php @unlink(__DIR__ . '/АБВ.txt'); diff --git a/ext/curl/tests/curl_copy_handle_variation4.phpt b/ext/curl/tests/curl_copy_handle_variation4.phpt new file mode 100644 index 0000000000..e160c06c64 --- /dev/null +++ b/ext/curl/tests/curl_copy_handle_variation4.phpt @@ -0,0 +1,46 @@ +--TEST-- +curl_copy_handle() allows to post CURLFile multiple times with curl_multi_exec() +--SKIPIF-- +<?php include 'skipif.inc'; ?> +--FILE-- +<?php +include 'server.inc'; +$host = curl_cli_server_start(); + +$ch1 = curl_init(); +curl_setopt($ch1, CURLOPT_SAFE_UPLOAD, 1); +curl_setopt($ch1, CURLOPT_URL, "{$host}/get.php?test=file"); +// curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1); + +$filename = __DIR__ . '/АБВ.txt'; +file_put_contents($filename, "Test."); +$file = curl_file_create($filename); +$params = array('file' => $file); +var_dump(curl_setopt($ch1, CURLOPT_POSTFIELDS, $params)); + +$ch2 = curl_copy_handle($ch1); +$ch3 = curl_copy_handle($ch1); + +$mh = curl_multi_init(); +curl_multi_add_handle($mh, $ch1); +curl_multi_add_handle($mh, $ch2); +do { + $status = curl_multi_exec($mh, $active); + if ($active) { + curl_multi_select($mh); + } +} while ($active && $status == CURLM_OK); + +curl_multi_remove_handle($mh, $ch1); +curl_multi_remove_handle($mh, $ch2); +curl_multi_remove_handle($mh, $ch3); +curl_multi_close($mh); +?> +===DONE=== +--EXPECTF-- +bool(true) +АБВ.txt|application/octet-stream|5АБВ.txt|application/octet-stream|5===DONE=== +--CLEAN-- +<?php +@unlink(__DIR__ . '/АБВ.txt'); +?> diff --git a/ext/curl/tests/curl_copy_handle_variation5.phpt b/ext/curl/tests/curl_copy_handle_variation5.phpt new file mode 100644 index 0000000000..019704e6c8 --- /dev/null +++ b/ext/curl/tests/curl_copy_handle_variation5.phpt @@ -0,0 +1,52 @@ +--TEST-- +curl_copy_handle() allows to post CURLFile multiple times if postfields change +--SKIPIF-- +<?php include 'skipif.inc'; ?> +--FILE-- +<?php +include 'server.inc'; +$host = curl_cli_server_start(); + +$ch1 = curl_init(); +curl_setopt($ch1, CURLOPT_SAFE_UPLOAD, 1); +curl_setopt($ch1, CURLOPT_URL, "{$host}/get.php?test=file"); +curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1); + +$filename = __DIR__ . '/abc.txt'; +file_put_contents($filename, "Test."); +$file = curl_file_create($filename); +$params = array('file' => $file); +var_dump(curl_setopt($ch1, CURLOPT_POSTFIELDS, $params)); + +$ch2 = curl_copy_handle($ch1); + +$filename = __DIR__ . '/def.txt'; +file_put_contents($filename, "Other test."); +$file = curl_file_create($filename); +$params = array('file' => $file); +var_dump(curl_setopt($ch2, CURLOPT_POSTFIELDS, $params)); + +$ch3 = curl_copy_handle($ch2); + +var_dump(curl_exec($ch1)); +curl_close($ch1); + +var_dump(curl_exec($ch2)); +curl_close($ch2); + +var_dump(curl_exec($ch3)); +curl_close($ch3); +?> +===DONE=== +--EXPECTF-- +bool(true) +bool(true) +string(%d) "abc.txt|application/octet-stream|5" +string(%d) "def.txt|application/octet-stream|11" +string(%d) "def.txt|application/octet-stream|11" +===DONE=== +--CLEAN-- +<?php +@unlink(__DIR__ . '/abc.txt'); +@unlink(__DIR__ . '/def.txt'); +?> diff --git a/ext/curl/tests/curl_file_upload.phpt b/ext/curl/tests/curl_file_upload.phpt index 2c6409a25b..e4a7c78251 100644 --- a/ext/curl/tests/curl_file_upload.phpt +++ b/ext/curl/tests/curl_file_upload.phpt @@ -60,15 +60,15 @@ var_dump(curl_exec($ch)); curl_close($ch); ?> --EXPECTF-- -string(%d) "curl_testdata1.txt|application/octet-stream" -string(%d) "curl_testdata1.txt|text/plain" -string(%d) "foo.txt|application/octet-stream" -string(%d) "foo.txt|text/plain" +string(%d) "curl_testdata1.txt|application/octet-stream|6" +string(%d) "curl_testdata1.txt|text/plain|6" +string(%d) "foo.txt|application/octet-stream|6" +string(%d) "foo.txt|text/plain|6" string(%d) "text/plain" string(%d) "%s/curl_testdata1.txt" -string(%d) "curl_testdata1.txt|text/plain" +string(%d) "curl_testdata1.txt|text/plain|6" string(%d) "foo.txt" -string(%d) "foo.txt|application/octet-stream" +string(%d) "foo.txt|application/octet-stream|6" Warning: curl_setopt(): Disabling safe uploads is no longer supported in %s on line %d string(0) "" diff --git a/ext/curl/tests/curl_file_upload_stream.phpt b/ext/curl/tests/curl_file_upload_stream.phpt index 0bbd87ff72..082130176d 100644 --- a/ext/curl/tests/curl_file_upload_stream.phpt +++ b/ext/curl/tests/curl_file_upload_stream.phpt @@ -23,4 +23,4 @@ curl_close($ch); ?> --EXPECT-- bool(true) -string(21) "i-love-php|text/plain" +string(24) "i-love-php|text/plain|11" diff --git a/ext/curl/tests/responder/get.inc b/ext/curl/tests/responder/get.inc index f9269745f6..64ab267d50 100644 --- a/ext/curl/tests/responder/get.inc +++ b/ext/curl/tests/responder/get.inc @@ -28,7 +28,7 @@ break; case 'file': if (isset($_FILES['file'])) { - echo $_FILES['file']['name'] . '|' . $_FILES['file']['type']; + echo $_FILES['file']['name'] . '|' . $_FILES['file']['type'] . '|' . $_FILES['file']['size']; } break; case 'method': |