@@ -1797,8 +1797,14 @@ static void curl_free_post(void **post)
17971797/* }}} */
17981798
17991799struct mime_file {
1800- zend_string * name ;
1801- php_stream * stream ;
1800+ php_curl * ch ;
1801+ union {
1802+ zval postfields ;
1803+ struct {
1804+ zend_string * name ;
1805+ php_stream * stream ;
1806+ };
1807+ };
18021808};
18031809
18041810/* {{{ curl_free_stream
@@ -1807,8 +1813,12 @@ static void curl_free_stream(void **post)
18071813{
18081814 struct mime_file * mime_file = (struct mime_file * ) * post ;
18091815
1810- ZEND_ASSERT (mime_file -> stream == NULL );
1811- zend_string_release (mime_file -> name );
1816+ if (mime_file -> ch ) {
1817+ Z_DELREF (mime_file -> postfields );
1818+ } else {
1819+ ZEND_ASSERT (mime_file -> stream == NULL );
1820+ zend_string_release (mime_file -> name );
1821+ }
18121822 efree (mime_file );
18131823}
18141824/* }}} */
@@ -2104,13 +2114,148 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
21042114 (* source -> clone )++ ;
21052115}
21062116
2117+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2118+ static size_t read_cb (char * buffer , size_t size , size_t nitems , void * arg );
2119+ static int seek_cb (void * arg , curl_off_t offset , int origin );
2120+ static void free_cb (void * arg );
2121+
2122+ static int rebuild_mime_structure (php_curl * ch , zval * zpostfields )
2123+ {
2124+ CURLcode error = CURLE_OK ;
2125+ zval * current ;
2126+ zend_string * string_key ;
2127+ zend_ulong num_key ;
2128+ curl_mime * mime = NULL ;
2129+ curl_mimepart * part ;
2130+ CURLcode form_error ;
2131+ HashTable * postfields = Z_ARRVAL_P (zpostfields );
2132+
2133+ if (zend_hash_num_elements (postfields ) > 0 ) {
2134+ mime = curl_mime_init (ch -> cp );
2135+ if (mime == NULL ) {
2136+ return FAILURE ;
2137+ }
2138+ }
2139+
2140+ ZEND_HASH_FOREACH_KEY_VAL (postfields , num_key , string_key , current ) {
2141+ zend_string * postval , * tmp_postval ;
2142+ /* Pretend we have a string_key here */
2143+ if (!string_key ) {
2144+ string_key = zend_long_to_str (num_key );
2145+ } else {
2146+ zend_string_addref (string_key );
2147+ }
2148+
2149+ ZVAL_DEREF (current );
2150+ if (Z_TYPE_P (current ) == IS_OBJECT &&
2151+ instanceof_function (Z_OBJCE_P (current ), curl_CURLFile_class )) {
2152+ /* new-style file upload */
2153+ zval * prop , rv ;
2154+ char * type = NULL , * filename = NULL ;
2155+
2156+ struct mime_file * mime_file ;
2157+
2158+
2159+ prop = zend_read_property (curl_CURLFile_class , current , "name" , sizeof ("name" )- 1 , 0 , & rv );
2160+ if (Z_TYPE_P (prop ) != IS_STRING ) {
2161+ php_error_docref (NULL , E_WARNING , "Invalid filename for key %s" , ZSTR_VAL (string_key ));
2162+ } else {
2163+ postval = Z_STR_P (prop );
2164+
2165+ if (php_check_open_basedir (ZSTR_VAL (postval ))) {
2166+ return 1 ;
2167+ }
2168+
2169+ prop = zend_read_property (curl_CURLFile_class , current , "mime" , sizeof ("mime" )- 1 , 0 , & rv );
2170+ if (Z_TYPE_P (prop ) == IS_STRING && Z_STRLEN_P (prop ) > 0 ) {
2171+ type = Z_STRVAL_P (prop );
2172+ }
2173+ prop = zend_read_property (curl_CURLFile_class , current , "postname" , sizeof ("postname" )- 1 , 0 , & rv );
2174+ if (Z_TYPE_P (prop ) == IS_STRING && Z_STRLEN_P (prop ) > 0 ) {
2175+ filename = Z_STRVAL_P (prop );
2176+ }
2177+
2178+ mime_file = emalloc (sizeof * mime_file );
2179+ mime_file -> ch = ch ;
2180+ ZVAL_COPY (& mime_file -> postfields , zpostfields );
2181+ zend_llist_add_element (& ch -> to_free -> stream , & mime_file );
2182+
2183+ mime_file = emalloc (sizeof * mime_file );
2184+ mime_file -> ch = NULL ;
2185+ mime_file -> name = zend_string_copy (postval );
2186+ mime_file -> stream = NULL ;
2187+ part = curl_mime_addpart (mime );
2188+ if (part == NULL ) {
2189+ zend_string_release_ex (string_key , 0 );
2190+ return FAILURE ;
2191+ }
2192+ if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2193+ || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , free_cb , mime_file )) != CURLE_OK
2194+ || (form_error = curl_mime_filename (part , filename ? filename : ZSTR_VAL (postval ))) != CURLE_OK
2195+ || (form_error = curl_mime_type (part , type ? type : "application/octet-stream" )) != CURLE_OK ) {
2196+ error = form_error ;
2197+ }
2198+ zend_llist_add_element (& ch -> to_free -> stream , & mime_file );
2199+ }
2200+
2201+ zend_string_release_ex (string_key , 0 );
2202+ continue ;
2203+ }
2204+
2205+ postval = zval_get_tmp_string (current , & tmp_postval );
2206+
2207+ part = curl_mime_addpart (mime );
2208+ if (part == NULL ) {
2209+ zend_tmp_string_release (tmp_postval );
2210+ zend_string_release_ex (string_key , 0 );
2211+ return FAILURE ;
2212+ }
2213+ if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2214+ || (form_error = curl_mime_data (part , ZSTR_VAL (postval ), ZSTR_LEN (postval ))) != CURLE_OK ) {
2215+ error = form_error ;
2216+ }
2217+ zend_tmp_string_release (tmp_postval );
2218+ zend_string_release_ex (string_key , 0 );
2219+ } ZEND_HASH_FOREACH_END ();
2220+
2221+ SAVE_CURL_ERROR (ch , error );
2222+ if (error != CURLE_OK ) {
2223+ return FAILURE ;
2224+ }
2225+
2226+ if ((* ch -> clone ) == 1 ) {
2227+ zend_llist_clean (& ch -> to_free -> post );
2228+ }
2229+ zend_llist_add_element (& ch -> to_free -> post , & mime );
2230+ error = curl_easy_setopt (ch -> cp , CURLOPT_MIMEPOST , mime );
2231+
2232+ return SUCCESS ;
2233+ }
2234+
2235+ static HashTable * get_postfields_of_handle (php_curl * ch )
2236+ {
2237+ struct mime_file * mime_file , * * mfp ;
2238+
2239+ mfp = zend_llist_get_last (& ch -> to_free -> stream );
2240+ while (mfp ) {
2241+ mime_file = * mfp ;
2242+ if (mime_file -> ch == ch ) {
2243+ return & mime_file -> postfields ;
2244+ }
2245+ mfp = zend_llist_get_prev (& ch -> to_free -> stream );
2246+ }
2247+ return NULL ;
2248+ }
2249+ #endif
2250+
21072251/* {{{ proto resource curl_copy_handle(resource ch)
21082252 Copy a cURL handle along with all of it's preferences */
21092253PHP_FUNCTION (curl_copy_handle )
21102254{
21112255 CURL * cp ;
21122256 zval * zid ;
21132257 php_curl * ch , * dupch ;
2258+ zval * postfields ;
21142259
21152260 ZEND_PARSE_PARAMETERS_START (1 ,1 )
21162261 Z_PARAM_RESOURCE (zid )
@@ -2131,6 +2276,17 @@ PHP_FUNCTION(curl_copy_handle)
21312276
21322277 _php_setup_easy_copy_handlers (dupch , ch );
21332278
2279+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
2280+ postfields = get_postfields_of_handle (ch );
2281+ if (postfields ) {
2282+ if (rebuild_mime_structure (dupch , postfields ) != SUCCESS ) {
2283+ _php_curl_close_ex (dupch );
2284+ php_error_docref (NULL , E_WARNING , "Cannot rebuild mime structure" );
2285+ RETURN_FALSE ;
2286+ }
2287+ }
2288+ #endif
2289+
21342290 Z_ADDREF_P (zid );
21352291
21362292 ZVAL_RES (return_value , zend_register_resource (dupch , le_curl ));
@@ -2144,13 +2300,15 @@ static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{
21442300 struct mime_file * mime_file = (struct mime_file * ) arg ;
21452301 ssize_t numread ;
21462302
2303+ ZEND_ASSERT (!mime_file -> ch );
2304+
21472305 if (mime_file -> stream == NULL ) {
21482306 if (!(mime_file -> stream = php_stream_open_wrapper (ZSTR_VAL (mime_file -> name ), "rb" , IGNORE_PATH , NULL ))) {
21492307 return CURL_READFUNC_ABORT ;
21502308 }
21512309 }
21522310 numread = php_stream_read (mime_file -> stream , buffer , nitems * size );
2153- if (numread <= 0 ) {
2311+ if (numread < 0 ) {
21542312 php_stream_close (mime_file -> stream );
21552313 mime_file -> stream = NULL ;
21562314 }
@@ -2163,17 +2321,28 @@ static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */
21632321 struct mime_file * mime_file = (struct mime_file * ) arg ;
21642322 int res ;
21652323
2324+ ZEND_ASSERT (!mime_file -> ch );
2325+
21662326 if (mime_file -> stream == NULL ) {
21672327 if (!(mime_file -> stream = php_stream_open_wrapper (ZSTR_VAL (mime_file -> name ), "rb" , IGNORE_PATH , NULL ))) {
21682328 return CURL_SEEKFUNC_CANTSEEK ;
21692329 }
21702330 }
21712331 res = php_stream_seek (mime_file -> stream , offset , origin );
2172- if (res ) {
2332+ return !res ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK ;
2333+ }
2334+ /* }}} */
2335+
2336+ static void free_cb (void * arg ) /* {{{ */
2337+ {
2338+ struct mime_file * mime_file = (struct mime_file * ) arg ;
2339+
2340+ ZEND_ASSERT (!mime_file -> ch );
2341+
2342+ if (mime_file -> stream != NULL ) {
21732343 php_stream_close (mime_file -> stream );
21742344 mime_file -> stream = NULL ;
21752345 }
2176- return !res ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK ;
21772346}
21782347/* }}} */
21792348#endif
@@ -2840,15 +3009,22 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
28403009
28413010#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
28423011 mime_file = emalloc (sizeof * mime_file );
3012+ mime_file -> ch = ch ;
3013+ ZVAL_COPY (& mime_file -> postfields , zvalue );
3014+ zend_llist_add_element (& ch -> to_free -> stream , & mime_file );
3015+
3016+ mime_file = emalloc (sizeof * mime_file );
3017+ mime_file -> ch = NULL ;
28433018 mime_file -> name = zend_string_copy (postval );
28443019 mime_file -> stream = NULL ;
3020+
28453021 part = curl_mime_addpart (mime );
28463022 if (part == NULL ) {
28473023 zend_string_release_ex (string_key , 0 );
28483024 return FAILURE ;
28493025 }
28503026 if ((form_error = curl_mime_name (part , ZSTR_VAL (string_key ))) != CURLE_OK
2851- || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , NULL , mime_file )) != CURLE_OK
3027+ || (form_error = curl_mime_data_cb (part , -1 , read_cb , seek_cb , free_cb , mime_file )) != CURLE_OK
28523028 || (form_error = curl_mime_filename (part , filename ? filename : ZSTR_VAL (postval ))) != CURLE_OK
28533029 || (form_error = curl_mime_type (part , type ? type : "application/octet-stream" )) != CURLE_OK ) {
28543030 error = form_error ;
0 commit comments