@@ -362,6 +362,7 @@ static bool php_stream_unwrap_content(php_stream_context *context, zend_string *
362362 } else if (Z_TYPE_P (content ) == IS_RESOURCE ) {
363363 * stream_out = php_stream_from_zval_no_verify_no_error (content );
364364 if (* stream_out ) {
365+ /* Note: at this point we don't know whether the stream is seekable, we can only know for sure by trying. */
365366 return true;
366367 } else {
367368 const char * space ;
@@ -374,21 +375,29 @@ static bool php_stream_unwrap_content(php_stream_context *context, zend_string *
374375 return false;
375376}
376377
377- static bool php_stream_append_content_length (smart_str * req_buf , zend_string * content_str , php_stream * content_stream )
378+ static bool php_stream_append_content_length (smart_str * req_buf , zend_string * * content_str , php_stream * * content_stream , bool * content_str_tmp )
378379{
379380 smart_str_appends (req_buf , "Content-Length: " );
380- if (content_str ) {
381- smart_str_append_unsigned (req_buf , ZSTR_LEN (content_str ));
381+ if (* content_str ) {
382+ smart_str_append_unsigned (req_buf , ZSTR_LEN (* content_str ));
382383 } else {
383- zend_off_t current_position = php_stream_tell (content_stream );
384- if (php_stream_seek (content_stream , 0 , SEEK_END ) < 0 ) {
385- return false;
386- }
387- zend_off_t end_position = php_stream_tell (content_stream );
388- if (php_stream_seek (content_stream , current_position , SEEK_SET ) < 0 ) {
389- return false;
384+ zend_off_t current_position = php_stream_tell (* content_stream );
385+ if (php_stream_seek (* content_stream , 0 , SEEK_END ) < 0 ) {
386+ * content_str = php_stream_copy_to_mem (* content_stream , PHP_STREAM_COPY_ALL , false);
387+ * content_stream = NULL ;
388+ if (* content_str ) {
389+ * content_str_tmp = true;
390+ smart_str_append_unsigned (req_buf , ZSTR_LEN (* content_str ));
391+ } else {
392+ return false;
393+ }
394+ } else {
395+ zend_off_t end_position = php_stream_tell (* content_stream );
396+ if (php_stream_seek (* content_stream , current_position , SEEK_SET ) < 0 ) {
397+ return false;
398+ }
399+ smart_str_append_unsigned (req_buf , end_position - current_position );
390400 }
391- smart_str_append_unsigned (req_buf , end_position - current_position );
392401 }
393402 smart_str_appends (req_buf , "\r\n" );
394403 return true;
@@ -876,6 +885,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
876885
877886 zend_string * content_str = NULL ;
878887 php_stream * content_stream = NULL ;
888+ bool content_str_tmp = false;
879889
880890 if (user_headers ) {
881891 /* A bit weird, but some servers require that Content-Length be sent prior to Content-Type for POST
@@ -887,7 +897,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
887897 !(have_header & HTTP_HEADER_CONTENT_LENGTH ) &&
888898 php_stream_unwrap_content (context , & content_str , & content_stream )
889899 ) {
890- if (!php_stream_append_content_length (& req_buf , content_str , content_stream )) {
900+ if (!php_stream_append_content_length (& req_buf , & content_str , & content_stream , & content_str_tmp )) {
891901 php_stream_close (stream );
892902 stream = NULL ;
893903 efree (user_headers );
@@ -903,6 +913,9 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
903913
904914 /* php_stream_unwrap_content() may throw a TypeError for non-stream resources */
905915 if (UNEXPECTED (EG (exception ))) {
916+ if (content_str_tmp ) {
917+ zend_string_efree (content_str );
918+ }
906919 php_stream_close (stream );
907920 stream = NULL ;
908921 goto out ;
@@ -913,7 +926,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
913926 if ((header_init || redirect_keep_method ) && context &&
914927 (content_str || content_stream || php_stream_unwrap_content (context , & content_str , & content_stream ))) {
915928 if (!(have_header & HTTP_HEADER_CONTENT_LENGTH )) {
916- if (!php_stream_append_content_length (& req_buf , content_str , content_stream )) {
929+ if (!php_stream_append_content_length (& req_buf , & content_str , & content_stream , & content_str_tmp )) {
917930 php_stream_close (stream );
918931 stream = NULL ;
919932 php_stream_wrapper_log_error (wrapper , options , "Unable to determine length of \"content\" stream!" );
@@ -928,6 +941,10 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
928941 if (content_str ) {
929942 smart_str_append (& req_buf , content_str );
930943 php_stream_write (stream , ZSTR_VAL (req_buf .s ), ZSTR_LEN (req_buf .s ));
944+
945+ if (content_str_tmp ) {
946+ zend_string_efree (content_str );
947+ }
931948 } else {
932949 php_stream_write (stream , ZSTR_VAL (req_buf .s ), ZSTR_LEN (req_buf .s ));
933950
0 commit comments