]> granicus.if.org Git - php/commitdiff
Fix #79013: Content-Length missing when posting a curlFile with curl
authorChristoph M. Becker <cmbecker69@gmx.de>
Mon, 2 Mar 2020 17:45:12 +0000 (18:45 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Mon, 2 Mar 2020 18:11:33 +0000 (19:11 +0100)
Unfortunately, some Webservers (e.g. IIS) do not implement the (F)CGI
specifications correctly wrt. chunked uploads (i.e. Transfer-encoding:
chunked), but instead pass -1 as CONTENT_LENGTH to the CGI
application. However, our (F)CFI SAPIs (i.e. cgi and cgi-fcgi) do not
support this.

Therefore we try to retrieve the stream size in advance and pass it to
`curl_mime_data_cb()` to prevent libcurl from doing chunked uploads.
This is basically the same approach that `curl_mime_filedata()`
implements, except that we are keeping already opened streams open for
the `read_cb()`.

NEWS
ext/curl/interface.c

diff --git a/NEWS b/NEWS
index 16802c2ea80e82e975da9ec684931f91ceccc010..7902b675226bf2430260cec5b3e4572b11d13054 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,8 @@ PHP                                                                        NEWS
 
 - CURL:
   . Fixed bug #79019 (Copied cURL handles upload empty file). (cmb)
+  . Fixed bug #79013 (Content-Length missing when posting a curlFile with
+    curl). (cmb)
 
 - DOM:
   . Fixed bug #77569: (Write Access Violation in DomImplementation). (Nikita,
index 668f7a71d9353a36c2e974bc2c82a971d7e394f9..45e41ba49ecbe75d784cf284e0cd9a06a30e1cdb 100644 (file)
@@ -2200,6 +2200,10 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
                        char *type = NULL, *filename = NULL;
 #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
                        struct mime_data_cb_arg *cb_arg;
+                       php_stream *stream;
+                       php_stream_statbuf ssb;
+                       size_t filesize = -1;
+                       curl_seek_callback seekfunc = seek_cb;
 #endif
 
                        prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv);
@@ -2225,9 +2229,17 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
                                zval_ptr_dtor(&ch->postfields);
                                ZVAL_COPY(&ch->postfields, zpostfields);
 
+                               if ((stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", STREAM_MUST_SEEK, NULL))) {
+                                       if (!stream->readfilters.head && !php_stream_stat(stream, &ssb)) {
+                                               filesize = ssb.sb.st_size;
+                                       }
+                               } else {
+                                       seekfunc = NULL;
+                               }
+
                                cb_arg = emalloc(sizeof *cb_arg);
                                cb_arg->filename = zend_string_copy(postval);
-                               cb_arg->stream = NULL;
+                               cb_arg->stream = stream;
 
                                part = curl_mime_addpart(mime);
                                if (part == NULL) {
@@ -2235,7 +2247,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
                                        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, free_cb, cb_arg)) != CURLE_OK
+                                       || (form_error = curl_mime_data_cb(part, filesize, read_cb, seekfunc, 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) {
                                        error = form_error;