@@ -1791,11 +1791,30 @@ static void curl_free_post(void **post)
17911791}
17921792/* }}} */
17931793
1794- /* {{{ curl_free_stream
1794+ struct mime_data_cb_arg {
1795+ php_curl * ch ;
1796+ union {
1797+ zval postfields ;
1798+ struct {
1799+ zend_string * filename ;
1800+ php_stream * stream ;
1801+ };
1802+ };
1803+ };
1804+
1805+ /* {{{ curl_free_cb_arg
17951806 */
1796- static void curl_free_stream (void * * post )
1807+ static void curl_free_cb_arg (void * * cb_arg_p )
17971808{
1798- php_stream_close ((php_stream * )* post );
1809+ struct mime_data_cb_arg * cb_arg = (struct mime_data_cb_arg * ) * cb_arg_p ;
1810+
1811+ if (cb_arg -> ch ) {
1812+ Z_DELREF (cb_arg -> postfields );
1813+ } else {
1814+ ZEND_ASSERT (cb_arg -> stream == NULL );
1815+ zend_string_release (cb_arg -> filename );
1816+ }
1817+ efree (cb_arg );
17991818}
18001819/* }}} */
18011820
@@ -1896,7 +1915,7 @@ php_curl *alloc_curl_handle()
18961915
18971916 zend_llist_init (& ch -> to_free -> str , sizeof (char * ), (llist_dtor_func_t )curl_free_string , 0 );
18981917 zend_llist_init (& ch -> to_free -> post , sizeof (struct HttpPost * ), (llist_dtor_func_t )curl_free_post , 0 );
1899- zend_llist_init (& ch -> to_free -> stream , sizeof (php_stream * ), (llist_dtor_func_t )curl_free_stream , 0 );
1918+ zend_llist_init (& ch -> to_free -> stream , sizeof (struct mime_data_cb_arg * ), (llist_dtor_func_t )curl_free_cb_arg , 0 );
19001919
19011920 ch -> to_free -> slist = emalloc (sizeof (HashTable ));
19021921 zend_hash_init (ch -> to_free -> slist , 4 , NULL , curl_free_slist , 0 );
@@ -2090,62 +2109,71 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
20902109 (* source -> clone )++ ;
20912110}
20922111
2093- /* {{{ proto resource curl_copy_handle(resource ch)
2094- Copy a cURL handle along with all of it's preferences */
2095- PHP_FUNCTION (curl_copy_handle )
2112+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2113+ static size_t read_cb (char * buffer , size_t size , size_t nitems , void * arg ) /* {{{ */
20962114{
2097- CURL * cp ;
2098- zval * zid ;
2099- php_curl * ch , * dupch ;
2115+ struct mime_data_cb_arg * cb_arg = (struct mime_data_cb_arg * ) arg ;
2116+ ssize_t numread ;
21002117
2101- ZEND_PARSE_PARAMETERS_START (1 ,1 )
2102- Z_PARAM_RESOURCE (zid )
2103- ZEND_PARSE_PARAMETERS_END ();
2118+ ZEND_ASSERT (!cb_arg -> ch );
21042119
2105- if ((ch = (php_curl * )zend_fetch_resource (Z_RES_P (zid ), le_curl_name , le_curl )) == NULL ) {
2106- RETURN_FALSE ;
2120+ if (cb_arg -> stream == NULL ) {
2121+ if (!(cb_arg -> stream = php_stream_open_wrapper (ZSTR_VAL (cb_arg -> filename ), "rb" , IGNORE_PATH , NULL ))) {
2122+ return CURL_READFUNC_ABORT ;
2123+ }
21072124 }
2108-
2109- cp = curl_easy_duphandle (ch -> cp );
2110- if (!cp ) {
2111- php_error_docref (NULL , E_WARNING , "Cannot duplicate cURL handle" );
2112- RETURN_FALSE ;
2125+ numread = php_stream_read (cb_arg -> stream , buffer , nitems * size );
2126+ if (numread < 0 ) {
2127+ php_stream_close (cb_arg -> stream );
2128+ cb_arg -> stream = NULL ;
21132129 }
2130+ return (numread >= 0 ) ? numread : CURL_READFUNC_ABORT ;
2131+ }
2132+ /* }}} */
21142133
2115- dupch = alloc_curl_handle ();
2116- dupch -> cp = cp ;
2117-
2118- _php_setup_easy_copy_handlers ( dupch , ch ) ;
2134+ static int seek_cb ( void * arg , curl_off_t offset , int origin ) /* {{{ */
2135+ {
2136+ struct mime_data_cb_arg * cb_arg = ( struct mime_data_cb_arg * ) arg ;
2137+ int res ;
21192138
2120- Z_ADDREF_P ( zid );
2139+ ZEND_ASSERT (! cb_arg -> ch );
21212140
2122- ZVAL_RES (return_value , zend_register_resource (dupch , le_curl ));
2123- dupch -> res = Z_RES_P (return_value );
2141+ if (cb_arg -> stream == NULL ) {
2142+ if (!(cb_arg -> stream = php_stream_open_wrapper (ZSTR_VAL (cb_arg -> filename ), "rb" , IGNORE_PATH , NULL ))) {
2143+ return CURL_SEEKFUNC_CANTSEEK ;
2144+ }
2145+ }
2146+ res = php_stream_seek (cb_arg -> stream , offset , origin );
2147+ return res == SUCCESS ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK ;
21242148}
21252149/* }}} */
21262150
2127- #if LIBCURL_VERSION_NUM >= 0x073800
2128- static size_t read_cb (char * buffer , size_t size , size_t nitems , void * arg ) /* {{{ */
2151+ static void free_cb (void * arg ) /* {{{ */
21292152{
2130- php_stream * stream = (php_stream * ) arg ;
2131- ssize_t numread = php_stream_read (stream , buffer , nitems * size );
2153+ struct mime_data_cb_arg * cb_arg = (struct mime_data_cb_arg * ) arg ;
21322154
2133- if (numread < 0 ) {
2134- return CURL_READFUNC_ABORT ;
2155+ ZEND_ASSERT (!cb_arg -> ch );
2156+
2157+ if (cb_arg -> stream != NULL ) {
2158+ php_stream_close (cb_arg -> stream );
2159+ cb_arg -> stream = NULL ;
21352160 }
2136- return numread ;
21372161}
21382162/* }}} */
21392163
2140- static int seek_cb ( void * arg , curl_off_t offset , int origin ) /* {{{ */
2164+ static zval * get_postfields_of_handle ( php_curl * ch ) /* {{{ */
21412165{
2142- php_stream * stream = (php_stream * ) arg ;
2143- int res = php_stream_seek (stream , offset , origin );
2166+ struct mime_data_cb_arg * cb_arg , * * cb_arg_p ;
21442167
2145- if (res ) {
2146- return CURL_SEEKFUNC_CANTSEEK ;
2168+ cb_arg_p = zend_llist_get_last (& ch -> to_free -> stream );
2169+ while (cb_arg_p ) {
2170+ cb_arg = * cb_arg_p ;
2171+ if (cb_arg -> ch == ch ) {
2172+ return & cb_arg -> postfields ;
2173+ }
2174+ cb_arg_p = zend_llist_get_prev (& ch -> to_free -> stream );
21472175 }
2148- return CURL_SEEKFUNC_OK ;
2176+ return NULL ;
21492177}
21502178/* }}} */
21512179#endif
@@ -2156,7 +2184,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
21562184 zval * current ;
21572185 HashTable * postfields ;
21582186 zend_string * string_key ;
2159- zend_ulong num_key ;
2187+ zend_ulong num_key ;
21602188#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
21612189 curl_mime * mime = NULL ;
21622190 curl_mimepart * part ;
@@ -2198,7 +2226,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
21982226 zval * prop , rv ;
21992227 char * type = NULL , * filename = NULL ;
22002228#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2201- php_stream * stream ;
2229+ struct mime_data_cb_arg * cb_arg ;
22022230#endif
22032231
22042232 prop = zend_read_property (curl_CURLFile_class , current , "name" , sizeof ("name" )- 1 , 0 , & rv );
@@ -2221,24 +2249,28 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
22212249 }
22222250
22232251#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2224- if (!(stream = php_stream_open_wrapper (ZSTR_VAL (postval ), "rb" , IGNORE_PATH , NULL ))) {
2225- zend_string_release_ex (string_key , 0 );
2226- return FAILURE ;
2227- }
2252+ cb_arg = emalloc (sizeof * cb_arg );
2253+ cb_arg -> ch = ch ;
2254+ ZVAL_COPY (& cb_arg -> postfields , zpostfields );
2255+ zend_llist_add_element (& ch -> to_free -> stream , & cb_arg );
2256+
2257+ cb_arg = emalloc (sizeof * cb_arg );
2258+ cb_arg -> ch = NULL ;
2259+ cb_arg -> filename = zend_string_copy (postval );
2260+ cb_arg -> stream = NULL ;
2261+
22282262 part = curl_mime_addpart (mime );
22292263 if (part == NULL ) {
2230- php_stream_close (stream );
22312264 zend_string_release_ex (string_key , 0 );
22322265 return FAILURE ;
22332266 }
22342267 if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2235- || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , NULL , stream )) != CURLE_OK
2268+ || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , free_cb , cb_arg )) != CURLE_OK
22362269 || (form_error = curl_mime_filename (part , filename ? filename : ZSTR_VAL (postval ))) != CURLE_OK
22372270 || (form_error = curl_mime_type (part , type ? type : "application/octet-stream" )) != CURLE_OK ) {
2238- php_stream_close (stream );
22392271 error = form_error ;
22402272 }
2241- zend_llist_add_element (& ch -> to_free -> stream , & stream );
2273+ zend_llist_add_element (& ch -> to_free -> stream , & cb_arg );
22422274#else
22432275 form_error = curl_formadd (& first , & last ,
22442276 CURLFORM_COPYNAME , ZSTR_VAL (string_key ),
@@ -2306,11 +2338,60 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
23062338 zend_llist_add_element (& ch -> to_free -> post , & first );
23072339 error = curl_easy_setopt (ch -> cp , CURLOPT_HTTPPOST , first );
23082340#endif
2341+
23092342 SAVE_CURL_ERROR (ch , error );
23102343 return error == CURLE_OK ? SUCCESS : FAILURE ;
23112344}
23122345/* }}} */
23132346
2347+ /* {{{ proto resource curl_copy_handle(resource ch)
2348+ Copy a cURL handle along with all of it's preferences */
2349+ PHP_FUNCTION (curl_copy_handle )
2350+ {
2351+ CURL * cp ;
2352+ zval * zid ;
2353+ php_curl * ch , * dupch ;
2354+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2355+ zval * postfields ;
2356+ #endif
2357+
2358+ ZEND_PARSE_PARAMETERS_START (1 ,1 )
2359+ Z_PARAM_RESOURCE (zid )
2360+ ZEND_PARSE_PARAMETERS_END ();
2361+
2362+ if ((ch = (php_curl * )zend_fetch_resource (Z_RES_P (zid ), le_curl_name , le_curl )) == NULL ) {
2363+ RETURN_FALSE ;
2364+ }
2365+
2366+ cp = curl_easy_duphandle (ch -> cp );
2367+ if (!cp ) {
2368+ php_error_docref (NULL , E_WARNING , "Cannot duplicate cURL handle" );
2369+ RETURN_FALSE ;
2370+ }
2371+
2372+ dupch = alloc_curl_handle ();
2373+ dupch -> cp = cp ;
2374+
2375+ _php_setup_easy_copy_handlers (dupch , ch );
2376+
2377+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2378+ postfields = get_postfields_of_handle (ch );
2379+ if (postfields ) {
2380+ if (build_mime_structure_from_hash (dupch , postfields ) != SUCCESS ) {
2381+ _php_curl_close_ex (dupch );
2382+ php_error_docref (NULL , E_WARNING , "Cannot rebuild mime structure" );
2383+ RETURN_FALSE ;
2384+ }
2385+ }
2386+ #endif
2387+
2388+ Z_ADDREF_P (zid );
2389+
2390+ ZVAL_RES (return_value , zend_register_resource (dupch , le_curl ));
2391+ dupch -> res = Z_RES_P (return_value );
2392+ }
2393+ /* }}} */
2394+
23142395static int _php_curl_setopt (php_curl * ch , zend_long option , zval * zvalue ) /* {{{ */
23152396{
23162397 CURLcode error = CURLE_OK ;
0 commit comments