Merge ~bryce/ubuntu/+source/php7.4:sru-lp1887826-curlfile-post-focal into ubuntu/+source/php7.4:ubuntu/focal-devel

Proposed by Bryce Harrington
Status: Merged
Approved by: Bryce Harrington
Approved revision: 6ad8d68d01f2ad47035910fe397db8724c849274
Merge reported by: Bryce Harrington
Merged at revision: 6ad8d68d01f2ad47035910fe397db8724c849274
Proposed branch: ~bryce/ubuntu/+source/php7.4:sru-lp1887826-curlfile-post-focal
Merge into: ubuntu/+source/php7.4:ubuntu/focal-devel
Diff against target: 615 lines (+587/-0)
4 files modified
debian/changelog (+15/-0)
debian/patches/0041-Fix-79019-Copied-cURL-handles-upload-empty-file.patch (+501/-0)
debian/patches/0042-Fix-79013-Content-Length-missing-when-posting-a-curl.patch (+68/-0)
debian/patches/series (+3/-0)
Reviewer Review Type Date Requested Status
Christian Ehrhardt  (community) Approve
Canonical Server Pending
Review via email: mp+390343@code.launchpad.net

Description of the change

This addresses a server-next requested SRU of a fix for "CURLFile POST missing Content-Length header" (LP: #1887826)

The upstream fix for the bug applies on top of another, related CURL fix, so I have included both.

PPA: https://launchpad.net/~bryce/+archive/ubuntu/php7.4-sru-lp1887826-curlfile-post

To post a comment you must log in.
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Changelog, Version, ... all look good to me.
The patches could use some headers again, but in this case one can recognize they are upstream patches and the hash is preserved, so I consider adding the headers optional.

I can recommend git-to-dquilt which does all that for you in one go.
https://git.launchpad.net/~ubuntu-server/ubuntu-helpers/tree/README.md#n63
but as I said optional in this case.

The patches are huge, give me a few minutes if they look SRU-compatible on closer examination.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

SRU Template is mostly good, but requires an [Regression Potential] still.

review: Needs Information
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Actually headers would be really nice, while I can find upstream from the patches, to know that they are for https://bugs.launchpad.net/ubuntu/+source/php7.4/+bug/1887826 forces me to re-read changelog on it. So if it isn't too much of a burden please add patch headers.

The changes are quite many, but if one excludes the tests no more.
0042 (the actual fix) is small and LGTM.
0041 (needed for the other to apply) - this one is much bigger. It has further different behavior if libcurl >7.56.0 which is true for Focal (7.68.0-1ubuntu2.2). After looking at it for a while I can say "the new code looks reasonable" but how much it is a departure from the former one I can't really say. Herein lies IMHO the biggest regression risk and you should put that into the SRU template.

Did you run these tests that got updated with the change? Might be build time checks ...

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Yeah all those tests ran on build
https://paste.ubuntu.com/p/S342JPswHS/

That gives some extra confidence boost.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Summary:
- quite a change but LGTM
- please add regression considerations to SRU
- if not too much add extended patch headers

Under these conditions +1 to that SRU

review: Approve
Revision history for this message
Bryce Harrington (bryce) wrote :

Thanks, I've added the DEP3 and force pushed, and updated the regression section on the SRU.

$ git push pkg focal-devel
Enumerating objects: 16, done.
Counting objects: 100% (16/16), done.
Delta compression using up to 12 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 7.08 KiB | 7.08 MiB/s, done.
Total 11 (delta 7), reused 0 (delta 0)
remote:
remote: Create a merge proposal for 'ubuntu/focal-devel' on Launchpad by visiting:
remote: https://code.launchpad.net/~usd-import-team/ubuntu/+source/php7.4/+git/php7.4/+ref/ubuntu/focal-devel/+register-merge
remote:
To ssh://git.launchpad.net/ubuntu/+source/php7.4
   f80afec1d..1e751b9f7 focal-devel -> ubuntu/focal-devel

$ dput ubuntu php7.4_7.4.3-4ubuntu2.3_source.changes
Checking signature on .changes
gpg: /home/bryce/pkg/Php7.4/sru-lp1887826-curlfile-post/php7.4_7.4.3-4ubuntu2.3_source.changes: Valid signature from E603B2578FB8F0FB
Checking signature on .dsc
gpg: /home/bryce/pkg/Php7.4/sru-lp1887826-curlfile-post/php7.4_7.4.3-4ubuntu2.3.dsc: Valid signature from E603B2578FB8F0FB
Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading php7.4_7.4.3-4ubuntu2.3.dsc: done.
  Uploading php7.4_7.4.3-4ubuntu2.3.debian.tar.xz: done.
  Uploading php7.4_7.4.3-4ubuntu2.3_source.buildinfo: done.
  Uploading php7.4_7.4.3-4ubuntu2.3_source.changes: done.
Successfully uploaded packages.

Revision history for this message
Bryce Harrington (bryce) wrote :

And per tests, yes with PHP I always do a full build, which runs the testsuite. The autopkgtests don't run locally (I think junk left by the build process confuses one of the tests) but the local build tends to catch most of the issues in practice.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

FYI Still in proposed:
 php7.4 | 7.4.3-4ubuntu2.3 | focal-proposed | source, all

Most seemed to be flaky arm boxes, but the fails on php-parser/4.2.2-2 are on all architectures and might need a look

Revision history for this message
Bryce Harrington (bryce) wrote :

Yes, I had looked at that a couple weeks back, it's this bug:

https://bugs.launchpad.net/ubuntu/+source/php-parser/+bug/1895878

Revision history for this message
Bryce Harrington (bryce) wrote :

This has migrated

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index c679a9c..6b4387b 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,18 @@
6+php7.4 (7.4.3-4ubuntu2.3~focal1) focal; urgency=medium
7+
8+ * ppa build for focal
9+
10+ -- Bryce Harrington <bryce@canonical.com> Fri, 04 Sep 2020 20:11:34 -0700
11+
12+php7.4 (7.4.3-4ubuntu2.3) focal; urgency=medium
13+
14+ * d/p/0041-Fix-79019-Copied-cURL-handles-upload-empty-file.patch,
15+ d/p/0042-Fix-79013-Content-Length-missing-when-posting-a-curl.patch:
16+ Fix issue with cURL causing chunked mode for file transfers.
17+ (LP: #1887826)
18+
19+ -- Bryce Harrington <bryce@canonical.com> Thu, 03 Sep 2020 13:06:34 -0700
20+
21 php7.4 (7.4.3-4ubuntu2.2) focal-security; urgency=medium
22
23 * SECURITY UPDATE: Denial of service through oversized memory allocated
24diff --git a/debian/patches/0041-Fix-79019-Copied-cURL-handles-upload-empty-file.patch b/debian/patches/0041-Fix-79019-Copied-cURL-handles-upload-empty-file.patch
25new file mode 100644
26index 0000000..94f9edf
27--- /dev/null
28+++ b/debian/patches/0041-Fix-79019-Copied-cURL-handles-upload-empty-file.patch
29@@ -0,0 +1,501 @@
30+From 2d0dec91a53bddbf9f9e09d9c58188515907d650 Mon Sep 17 00:00:00 2001
31+From: "Christoph M. Becker" <cmbecker69@gmx.de>
32+Date: Tue, 4 Feb 2020 11:01:33 +0100
33+Subject: [PATCH] Fix #79019: Copied cURL handles upload empty file
34+
35+To cater to `curl_copy_handle()` of cURL handles with attached
36+`CURLFile`s, we must not attach the opened stream, because the stream
37+may not be seekable, so that we could rewind, when the same stream is
38+going to be uploaded multiple times. Instead, we're opening the stream
39+lazily in the read callback.
40+
41+Since `curl_multi_perfom()` processes easy handles asynchronously, we
42+have no control of the operation sequence. Since duplicated cURL
43+handles may be used with multi handles, we cannot use a single arg
44+structure, but actually have to rebuild the whole mime structure on
45+handle duplication and attach this to the new handle.
46+
47+In order to better test this behavior, we extend the test responder to
48+print the size of the upload, and patch the existing tests accordingly.
49+
50+Origin: upstream, https://github.com/php/php-src/commit/2d0dec91a53bddbf9f9e09d9c58188515907d650
51+Bug: https://bugs.php.net/bug.php?id=79019
52+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/php7.4/+bug/1887826
53+
54+diff --git a/ext/curl/interface.c b/ext/curl/interface.c
55+index 07026e1d9c..668f7a71d9 100644
56+--- a/ext/curl/interface.c
57++++ b/ext/curl/interface.c
58+@@ -1795,11 +1795,20 @@ static void curl_free_post(void **post)
59+ }
60+ /* }}} */
61+
62+-/* {{{ curl_free_stream
63++struct mime_data_cb_arg {
64++ zend_string *filename;
65++ php_stream *stream;
66++};
67++
68++/* {{{ curl_free_cb_arg
69+ */
70+-static void curl_free_stream(void **post)
71++static void curl_free_cb_arg(void **cb_arg_p)
72+ {
73+- php_stream_close((php_stream *)*post);
74++ struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) *cb_arg_p;
75++
76++ ZEND_ASSERT(cb_arg->stream == NULL);
77++ zend_string_release(cb_arg->filename);
78++ efree(cb_arg);
79+ }
80+ /* }}} */
81+
82+@@ -1900,11 +1909,13 @@ php_curl *alloc_curl_handle()
83+
84+ zend_llist_init(&ch->to_free->str, sizeof(char *), (llist_dtor_func_t)curl_free_string, 0);
85+ zend_llist_init(&ch->to_free->post, sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post, 0);
86+- zend_llist_init(&ch->to_free->stream, sizeof(php_stream *), (llist_dtor_func_t)curl_free_stream, 0);
87++ zend_llist_init(&ch->to_free->stream, sizeof(struct mime_data_cb_arg *), (llist_dtor_func_t)curl_free_cb_arg, 0);
88+
89+ ch->to_free->slist = emalloc(sizeof(HashTable));
90+ zend_hash_init(ch->to_free->slist, 4, NULL, curl_free_slist, 0);
91+-
92++#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
93++ ZVAL_UNDEF(&ch->postfields);
94++#endif
95+ return ch;
96+ }
97+ /* }}} */
98+@@ -2094,62 +2105,48 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
99+ (*source->clone)++;
100+ }
101+
102+-/* {{{ proto resource curl_copy_handle(resource ch)
103+- Copy a cURL handle along with all of it's preferences */
104+-PHP_FUNCTION(curl_copy_handle)
105++#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
106++static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */
107+ {
108+- CURL *cp;
109+- zval *zid;
110+- php_curl *ch, *dupch;
111+-
112+- ZEND_PARSE_PARAMETERS_START(1,1)
113+- Z_PARAM_RESOURCE(zid)
114+- ZEND_PARSE_PARAMETERS_END();
115++ struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;
116++ ssize_t numread;
117+
118+- if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
119+- RETURN_FALSE;
120++ if (cb_arg->stream == NULL) {
121++ if (!(cb_arg->stream = php_stream_open_wrapper(ZSTR_VAL(cb_arg->filename), "rb", IGNORE_PATH, NULL))) {
122++ return CURL_READFUNC_ABORT;
123++ }
124+ }
125+-
126+- cp = curl_easy_duphandle(ch->cp);
127+- if (!cp) {
128+- php_error_docref(NULL, E_WARNING, "Cannot duplicate cURL handle");
129+- RETURN_FALSE;
130++ numread = php_stream_read(cb_arg->stream, buffer, nitems * size);
131++ if (numread < 0) {
132++ php_stream_close(cb_arg->stream);
133++ cb_arg->stream = NULL;
134++ return CURL_READFUNC_ABORT;
135+ }
136+-
137+- dupch = alloc_curl_handle();
138+- dupch->cp = cp;
139+-
140+- _php_setup_easy_copy_handlers(dupch, ch);
141+-
142+- Z_ADDREF_P(zid);
143+-
144+- ZVAL_RES(return_value, zend_register_resource(dupch, le_curl));
145+- dupch->res = Z_RES_P(return_value);
146++ return numread;
147+ }
148+ /* }}} */
149+
150+-#if LIBCURL_VERSION_NUM >= 0x073800
151+-static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */
152++static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */
153+ {
154+- php_stream *stream = (php_stream *) arg;
155+- ssize_t numread = php_stream_read(stream, buffer, nitems * size);
156++ struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;
157++ int res;
158+
159+- if (numread < 0) {
160+- return CURL_READFUNC_ABORT;
161++ if (cb_arg->stream == NULL) {
162++ return CURL_SEEKFUNC_CANTSEEK;
163+ }
164+- return numread;
165++ res = php_stream_seek(cb_arg->stream, offset, origin);
166++ return res == SUCCESS ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK;
167+ }
168+ /* }}} */
169+
170+-static int seek_cb(void *arg, curl_off_t offset, int origin) /* {{{ */
171++static void free_cb(void *arg) /* {{{ */
172+ {
173+- php_stream *stream = (php_stream *) arg;
174+- int res = php_stream_seek(stream, offset, origin);
175++ struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;
176+
177+- if (res) {
178+- return CURL_SEEKFUNC_CANTSEEK;
179++ if (cb_arg->stream != NULL) {
180++ php_stream_close(cb_arg->stream);
181++ cb_arg->stream = NULL;
182+ }
183+- return CURL_SEEKFUNC_OK;
184+ }
185+ /* }}} */
186+ #endif
187+@@ -2160,7 +2157,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
188+ zval *current;
189+ HashTable *postfields;
190+ zend_string *string_key;
191+- zend_ulong num_key;
192++ zend_ulong num_key;
193+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
194+ curl_mime *mime = NULL;
195+ curl_mimepart *part;
196+@@ -2202,7 +2199,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
197+ zval *prop, rv;
198+ char *type = NULL, *filename = NULL;
199+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
200+- php_stream *stream;
201++ struct mime_data_cb_arg *cb_arg;
202+ #endif
203+
204+ prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv);
205+@@ -2225,24 +2222,25 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
206+ }
207+
208+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
209+- if (!(stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", IGNORE_PATH, NULL))) {
210+- zend_string_release_ex(string_key, 0);
211+- return FAILURE;
212+- }
213++ zval_ptr_dtor(&ch->postfields);
214++ ZVAL_COPY(&ch->postfields, zpostfields);
215++
216++ cb_arg = emalloc(sizeof *cb_arg);
217++ cb_arg->filename = zend_string_copy(postval);
218++ cb_arg->stream = NULL;
219++
220+ part = curl_mime_addpart(mime);
221+ if (part == NULL) {
222+- php_stream_close(stream);
223+ zend_string_release_ex(string_key, 0);
224+ return FAILURE;
225+ }
226+ if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK
227+- || (form_error = curl_mime_data_cb(part, -1, read_cb, seek_cb, NULL, stream)) != CURLE_OK
228++ || (form_error = curl_mime_data_cb(part, -1, read_cb, seek_cb, free_cb, cb_arg)) != CURLE_OK
229+ || (form_error = curl_mime_filename(part, filename ? filename : ZSTR_VAL(postval))) != CURLE_OK
230+ || (form_error = curl_mime_type(part, type ? type : "application/octet-stream")) != CURLE_OK) {
231+- php_stream_close(stream);
232+ error = form_error;
233+ }
234+- zend_llist_add_element(&ch->to_free->stream, &stream);
235++ zend_llist_add_element(&ch->to_free->stream, &cb_arg);
236+ #else
237+ form_error = curl_formadd(&first, &last,
238+ CURLFORM_COPYNAME, ZSTR_VAL(string_key),
239+@@ -2310,11 +2308,60 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
240+ zend_llist_add_element(&ch->to_free->post, &first);
241+ error = curl_easy_setopt(ch->cp, CURLOPT_HTTPPOST, first);
242+ #endif
243++
244+ SAVE_CURL_ERROR(ch, error);
245+ return error == CURLE_OK ? SUCCESS : FAILURE;
246+ }
247+ /* }}} */
248+
249++/* {{{ proto resource curl_copy_handle(resource ch)
250++ Copy a cURL handle along with all of it's preferences */
251++PHP_FUNCTION(curl_copy_handle)
252++{
253++ CURL *cp;
254++ zval *zid;
255++ php_curl *ch, *dupch;
256++#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
257++ zval *postfields;
258++#endif
259++
260++ ZEND_PARSE_PARAMETERS_START(1,1)
261++ Z_PARAM_RESOURCE(zid)
262++ ZEND_PARSE_PARAMETERS_END();
263++
264++ if ((ch = (php_curl*)zend_fetch_resource(Z_RES_P(zid), le_curl_name, le_curl)) == NULL) {
265++ RETURN_FALSE;
266++ }
267++
268++ cp = curl_easy_duphandle(ch->cp);
269++ if (!cp) {
270++ php_error_docref(NULL, E_WARNING, "Cannot duplicate cURL handle");
271++ RETURN_FALSE;
272++ }
273++
274++ dupch = alloc_curl_handle();
275++ dupch->cp = cp;
276++
277++ _php_setup_easy_copy_handlers(dupch, ch);
278++
279++#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
280++ postfields = &ch->postfields;
281++ if (Z_TYPE_P(postfields) != IS_UNDEF) {
282++ if (build_mime_structure_from_hash(dupch, postfields) != SUCCESS) {
283++ _php_curl_close_ex(dupch);
284++ php_error_docref(NULL, E_WARNING, "Cannot rebuild mime structure");
285++ RETURN_FALSE;
286++ }
287++ }
288++#endif
289++
290++ Z_ADDREF_P(zid);
291++
292++ ZVAL_RES(return_value, zend_register_resource(dupch, le_curl));
293++ dupch->res = Z_RES_P(return_value);
294++}
295++/* }}} */
296++
297+ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ */
298+ {
299+ CURLcode error = CURLE_OK;
300+@@ -3613,6 +3660,9 @@ static void _php_curl_close_ex(php_curl *ch)
301+ #endif
302+
303+ efree(ch->handlers);
304++#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
305++ zval_ptr_dtor(&ch->postfields);
306++#endif
307+ efree(ch);
308+ }
309+ /* }}} */
310+diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h
311+index 5d93f16c03..f4f722e134 100644
312+--- a/ext/curl/php_curl.h
313++++ b/ext/curl/php_curl.h
314+@@ -183,6 +183,9 @@ typedef struct {
315+ struct _php_curl_error err;
316+ zend_bool in_callback;
317+ uint32_t* clone;
318++#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
319++ zval postfields;
320++#endif
321+ } php_curl;
322+
323+ #define CURLOPT_SAFE_UPLOAD -1
324+diff --git a/ext/curl/tests/bug27023.phpt b/ext/curl/tests/bug27023.phpt
325+index 3d649b3f73..f985c192b8 100644
326+--- a/ext/curl/tests/bug27023.phpt
327++++ b/ext/curl/tests/bug27023.phpt
328+@@ -38,7 +38,7 @@ var_dump(curl_exec($ch));
329+ curl_close($ch);
330+ ?>
331+ --EXPECTF--
332+-string(%d) "curl_testdata1.txt|application/octet-stream"
333+-string(%d) "curl_testdata1.txt|text/plain"
334+-string(%d) "foo.txt|application/octet-stream"
335+-string(%d) "foo.txt|text/plain"
336++string(%d) "curl_testdata1.txt|application/octet-stream|6"
337++string(%d) "curl_testdata1.txt|text/plain|6"
338++string(%d) "foo.txt|application/octet-stream|6"
339++string(%d) "foo.txt|text/plain|6"
340+diff --git a/ext/curl/tests/bug77711.phpt b/ext/curl/tests/bug77711.phpt
341+index 148c26322a..8ef5e48891 100644
342+--- a/ext/curl/tests/bug77711.phpt
343++++ b/ext/curl/tests/bug77711.phpt
344+@@ -24,7 +24,7 @@ curl_close($ch);
345+ ===DONE===
346+ --EXPECTF--
347+ bool(true)
348+-string(%d) "АБВ.txt|application/octet-stream"
349++string(%d) "АБВ.txt|application/octet-stream|5"
350+ ===DONE===
351+ --CLEAN--
352+ <?php
353+diff --git a/ext/curl/tests/curl_copy_handle_variation3.phpt b/ext/curl/tests/curl_copy_handle_variation3.phpt
354+index 18f35f71b1..32946bb4df 100644
355+--- a/ext/curl/tests/curl_copy_handle_variation3.phpt
356++++ b/ext/curl/tests/curl_copy_handle_variation3.phpt
357+@@ -29,8 +29,8 @@ curl_close($ch2);
358+ ===DONE===
359+ --EXPECTF--
360+ bool(true)
361+-string(%d) "АБВ.txt|application/octet-stream"
362+-string(%d) "АБВ.txt|application/octet-stream"
363++string(%d) "АБВ.txt|application/octet-stream|5"
364++string(%d) "АБВ.txt|application/octet-stream|5"
365+ ===DONE===
366+ --CLEAN--
367+ <?php
368+diff --git a/ext/curl/tests/curl_copy_handle_variation4.phpt b/ext/curl/tests/curl_copy_handle_variation4.phpt
369+new file mode 100644
370+index 0000000000..e160c06c64
371+--- /dev/null
372++++ b/ext/curl/tests/curl_copy_handle_variation4.phpt
373+@@ -0,0 +1,46 @@
374++--TEST--
375++curl_copy_handle() allows to post CURLFile multiple times with curl_multi_exec()
376++--SKIPIF--
377++<?php include 'skipif.inc'; ?>
378++--FILE--
379++<?php
380++include 'server.inc';
381++$host = curl_cli_server_start();
382++
383++$ch1 = curl_init();
384++curl_setopt($ch1, CURLOPT_SAFE_UPLOAD, 1);
385++curl_setopt($ch1, CURLOPT_URL, "{$host}/get.php?test=file");
386++// curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);
387++
388++$filename = __DIR__ . '/АБВ.txt';
389++file_put_contents($filename, "Test.");
390++$file = curl_file_create($filename);
391++$params = array('file' => $file);
392++var_dump(curl_setopt($ch1, CURLOPT_POSTFIELDS, $params));
393++
394++$ch2 = curl_copy_handle($ch1);
395++$ch3 = curl_copy_handle($ch1);
396++
397++$mh = curl_multi_init();
398++curl_multi_add_handle($mh, $ch1);
399++curl_multi_add_handle($mh, $ch2);
400++do {
401++ $status = curl_multi_exec($mh, $active);
402++ if ($active) {
403++ curl_multi_select($mh);
404++ }
405++} while ($active && $status == CURLM_OK);
406++
407++curl_multi_remove_handle($mh, $ch1);
408++curl_multi_remove_handle($mh, $ch2);
409++curl_multi_remove_handle($mh, $ch3);
410++curl_multi_close($mh);
411++?>
412++===DONE===
413++--EXPECTF--
414++bool(true)
415++АБВ.txt|application/octet-stream|5АБВ.txt|application/octet-stream|5===DONE===
416++--CLEAN--
417++<?php
418++@unlink(__DIR__ . '/АБВ.txt');
419++?>
420+diff --git a/ext/curl/tests/curl_copy_handle_variation5.phpt b/ext/curl/tests/curl_copy_handle_variation5.phpt
421+new file mode 100644
422+index 0000000000..019704e6c8
423+--- /dev/null
424++++ b/ext/curl/tests/curl_copy_handle_variation5.phpt
425+@@ -0,0 +1,52 @@
426++--TEST--
427++curl_copy_handle() allows to post CURLFile multiple times if postfields change
428++--SKIPIF--
429++<?php include 'skipif.inc'; ?>
430++--FILE--
431++<?php
432++include 'server.inc';
433++$host = curl_cli_server_start();
434++
435++$ch1 = curl_init();
436++curl_setopt($ch1, CURLOPT_SAFE_UPLOAD, 1);
437++curl_setopt($ch1, CURLOPT_URL, "{$host}/get.php?test=file");
438++curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);
439++
440++$filename = __DIR__ . '/abc.txt';
441++file_put_contents($filename, "Test.");
442++$file = curl_file_create($filename);
443++$params = array('file' => $file);
444++var_dump(curl_setopt($ch1, CURLOPT_POSTFIELDS, $params));
445++
446++$ch2 = curl_copy_handle($ch1);
447++
448++$filename = __DIR__ . '/def.txt';
449++file_put_contents($filename, "Other test.");
450++$file = curl_file_create($filename);
451++$params = array('file' => $file);
452++var_dump(curl_setopt($ch2, CURLOPT_POSTFIELDS, $params));
453++
454++$ch3 = curl_copy_handle($ch2);
455++
456++var_dump(curl_exec($ch1));
457++curl_close($ch1);
458++
459++var_dump(curl_exec($ch2));
460++curl_close($ch2);
461++
462++var_dump(curl_exec($ch3));
463++curl_close($ch3);
464++?>
465++===DONE===
466++--EXPECTF--
467++bool(true)
468++bool(true)
469++string(%d) "abc.txt|application/octet-stream|5"
470++string(%d) "def.txt|application/octet-stream|11"
471++string(%d) "def.txt|application/octet-stream|11"
472++===DONE===
473++--CLEAN--
474++<?php
475++@unlink(__DIR__ . '/abc.txt');
476++@unlink(__DIR__ . '/def.txt');
477++?>
478+diff --git a/ext/curl/tests/curl_file_upload.phpt b/ext/curl/tests/curl_file_upload.phpt
479+index 73a2f363fb..1626f8117c 100644
480+--- a/ext/curl/tests/curl_file_upload.phpt
481++++ b/ext/curl/tests/curl_file_upload.phpt
482+@@ -60,15 +60,15 @@ var_dump(curl_exec($ch));
483+ curl_close($ch);
484+ ?>
485+ --EXPECTF--
486+-string(%d) "curl_testdata1.txt|application/octet-stream"
487+-string(%d) "curl_testdata1.txt|text/plain"
488+-string(%d) "foo.txt|application/octet-stream"
489+-string(%d) "foo.txt|text/plain"
490++string(%d) "curl_testdata1.txt|application/octet-stream|6"
491++string(%d) "curl_testdata1.txt|text/plain|6"
492++string(%d) "foo.txt|application/octet-stream|6"
493++string(%d) "foo.txt|text/plain|6"
494+ string(%d) "text/plain"
495+ string(%d) "%s/curl_testdata1.txt"
496+-string(%d) "curl_testdata1.txt|text/plain"
497++string(%d) "curl_testdata1.txt|text/plain|6"
498+ string(%d) "foo.txt"
499+-string(%d) "foo.txt|application/octet-stream"
500++string(%d) "foo.txt|application/octet-stream|6"
501+
502+ Warning: curl_setopt(): Disabling safe uploads is no longer supported in %s on line %d
503+ string(0) ""
504+diff --git a/ext/curl/tests/curl_file_upload_stream.phpt b/ext/curl/tests/curl_file_upload_stream.phpt
505+index 03c85b4b82..949cccbc31 100644
506+--- a/ext/curl/tests/curl_file_upload_stream.phpt
507++++ b/ext/curl/tests/curl_file_upload_stream.phpt
508+@@ -24,5 +24,5 @@ curl_close($ch);
509+ ===DONE===
510+ --EXPECT--
511+ bool(true)
512+-string(21) "i-love-php|text/plain"
513++string(24) "i-love-php|text/plain|11"
514+ ===DONE===
515+diff --git a/ext/curl/tests/responder/get.inc b/ext/curl/tests/responder/get.inc
516+index f9269745f6..64ab267d50 100644
517+--- a/ext/curl/tests/responder/get.inc
518++++ b/ext/curl/tests/responder/get.inc
519+@@ -28,7 +28,7 @@
520+ break;
521+ case 'file':
522+ if (isset($_FILES['file'])) {
523+- echo $_FILES['file']['name'] . '|' . $_FILES['file']['type'];
524++ echo $_FILES['file']['name'] . '|' . $_FILES['file']['type'] . '|' . $_FILES['file']['size'];
525+ }
526+ break;
527+ case 'method':
528+--
529+2.25.1
530+
531diff --git a/debian/patches/0042-Fix-79013-Content-Length-missing-when-posting-a-curl.patch b/debian/patches/0042-Fix-79013-Content-Length-missing-when-posting-a-curl.patch
532new file mode 100644
533index 0000000..a2bfafc
534--- /dev/null
535+++ b/debian/patches/0042-Fix-79013-Content-Length-missing-when-posting-a-curl.patch
536@@ -0,0 +1,68 @@
537+From fc8b3ab7cbb4f5e77584babeaf25b9bf16f524cd Mon Sep 17 00:00:00 2001
538+From: "Christoph M. Becker" <cmbecker69@gmx.de>
539+Date: Mon, 2 Mar 2020 18:45:12 +0100
540+Subject: [PATCH] Fix #79013: Content-Length missing when posting a curlFile
541+ with curl
542+
543+Unfortunately, some Webservers (e.g. IIS) do not implement the (F)CGI
544+specifications correctly wrt. chunked uploads (i.e. Transfer-encoding:
545+chunked), but instead pass -1 as CONTENT_LENGTH to the CGI
546+application. However, our (F)CFI SAPIs (i.e. cgi and cgi-fcgi) do not
547+support this.
548+
549+Therefore we try to retrieve the stream size in advance and pass it to
550+`curl_mime_data_cb()` to prevent libcurl from doing chunked uploads.
551+This is basically the same approach that `curl_mime_filedata()`
552+implements, except that we are keeping already opened streams open for
553+the `read_cb()`.
554+
555+Origin: upstream, https://github.com/php/php-src/commit/fc8b3ab7cbb4f5e77584babeaf25b9bf16f524cd
556+Bug: https://bugs.php.net/bug.php?id=79013
557+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/php7.4/+bug/1887826
558+
559+diff --git a/ext/curl/interface.c b/ext/curl/interface.c
560+index 668f7a71d9..45e41ba49e 100644
561+--- a/ext/curl/interface.c
562++++ b/ext/curl/interface.c
563+@@ -2200,6 +2200,10 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
564+ char *type = NULL, *filename = NULL;
565+ #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
566+ struct mime_data_cb_arg *cb_arg;
567++ php_stream *stream;
568++ php_stream_statbuf ssb;
569++ size_t filesize = -1;
570++ curl_seek_callback seekfunc = seek_cb;
571+ #endif
572+
573+ prop = zend_read_property(curl_CURLFile_class, current, "name", sizeof("name")-1, 0, &rv);
574+@@ -2225,9 +2229,17 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
575+ zval_ptr_dtor(&ch->postfields);
576+ ZVAL_COPY(&ch->postfields, zpostfields);
577+
578++ if ((stream = php_stream_open_wrapper(ZSTR_VAL(postval), "rb", STREAM_MUST_SEEK, NULL))) {
579++ if (!stream->readfilters.head && !php_stream_stat(stream, &ssb)) {
580++ filesize = ssb.sb.st_size;
581++ }
582++ } else {
583++ seekfunc = NULL;
584++ }
585++
586+ cb_arg = emalloc(sizeof *cb_arg);
587+ cb_arg->filename = zend_string_copy(postval);
588+- cb_arg->stream = NULL;
589++ cb_arg->stream = stream;
590+
591+ part = curl_mime_addpart(mime);
592+ if (part == NULL) {
593+@@ -2235,7 +2247,7 @@ static inline int build_mime_structure_from_hash(php_curl *ch, zval *zpostfields
594+ return FAILURE;
595+ }
596+ if ((form_error = curl_mime_name(part, ZSTR_VAL(string_key))) != CURLE_OK
597+- || (form_error = curl_mime_data_cb(part, -1, read_cb, seek_cb, free_cb, cb_arg)) != CURLE_OK
598++ || (form_error = curl_mime_data_cb(part, filesize, read_cb, seekfunc, free_cb, cb_arg)) != CURLE_OK
599+ || (form_error = curl_mime_filename(part, filename ? filename : ZSTR_VAL(postval))) != CURLE_OK
600+ || (form_error = curl_mime_type(part, type ? type : "application/octet-stream")) != CURLE_OK) {
601+ error = form_error;
602+--
603+2.25.1
604+
605diff --git a/debian/patches/series b/debian/patches/series
606index 6b41753..6237d6a 100644
607--- a/debian/patches/series
608+++ b/debian/patches/series
609@@ -42,3 +42,6 @@ CVE-2020-7064.patch
610 CVE-2020-7065.patch
611 CVE-2020-7066.patch
612 CVE-2019-11048.patch
613+
614+0041-Fix-79019-Copied-cURL-handles-upload-empty-file.patch
615+0042-Fix-79013-Content-Length-missing-when-posting-a-curl.patch

Subscribers

People subscribed via source and target branches