Skip to content

Fix #79019: Copied cURL handles upload empty file #5045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

cmb69
Copy link
Member

@cmb69 cmb69 commented Dec 31, 2019

To cater to curl_copy_handle() of cURL handles with attached
CURLFiles, we must not attach the opened stream, because the stream
may not be seekable, so that we could rewind, when the same stream is
going to be uploaded multiple times. Instead, we're opening the stream
lazily in the read or seek callback, and close it when reading finished
(either successfully or not) and when seeking failed, respectively.

This behavior is basically the same as for libcurl < 7.56.0, where we
attach the file name, and libcurl reads and uploads the file contents.

To be able to test this behavior, we extend the test responder to print
the size of the upload, and patch the existing tests accordingly.


I have targeted PHP-7.4, although the CURLFile stream support has recently been back-ported to PHP-7.3, so this branch is affected by bug 79019 as well. However, particularly after this patch, I don't think that we could reasonably fix bug 79013, so I suggest to revert commit 17a9f14 (note that this commit has not yet been released) but keep e120273, and stick with the chunked upload for PHP-7.4+ and change bug 79013 to documentation problem.

@cmb69 cmb69 added the Bug label Dec 31, 2019
Copy link
Member

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How sure are we that the stream is going to get closed? Can there be conditions (say a timeout while curl is sending) that prevent the stream from being fully consumed?

@cmb69
Copy link
Member Author

cmb69 commented Jan 2, 2020

Good question! I've just sent a mail to the curl-library list. Let's see.

@cmb69
Copy link
Member Author

cmb69 commented Jan 8, 2020

After some helpful discussion on the curl mailing list, I came up with a more comprehensive solution which is supposed to work with curl_copy_handle() and curl_multi_exec() (particularly regarding the latter the approaches so far could not have worked). The relevant commit is 512ce49; the following commits are just minor refactorings.

It has to be noted that this solution uses a hack to keep BC for PHP-7.4; after merging into master that hack should be removed. Also, it is important to point out that the current solution uses an anonymous union and struct, so it is easier to port to a better solution in master. Anonymous unions and struct actually require C11 (or an appropriate subset thereof), but I think that we're using anonymous unions/struct already in PHP-7.4. Please correct me if I'm wrong.

php-pulls pushed a commit that referenced this pull request Jan 8, 2020
As suggested by Nikita[1].

[1] <#5045 (comment)>
To cater to `curl_copy_handle()` of cURL handles with attached
`CURLFile`s, we must not attach the opened stream, because the stream
may not be seekable, so that we could rewind, when the same stream is
going to be uploaded multiple times.  Instead, we're opening the stream
lazily in the read or seek callback.

Since `curl_multi_perfom()` processes easy handles asynchronously, we
have no control of the operation sequence.  Since duplicated cURL
handles may be used with multi handles, we cannot use a single arg
structure, but actually have to rebuild the whole mime structure on
handle duplication and attach this to the new handle.

This requires to store the zval that has been originally provided for
`CURLOPT_POSTFIELDS`.  Ideally, we would store it in an additional
member of `php_curl`, but since that would constitute a BC break, we
work around by actually storing a union in `to_free->stream`, and we
retrieve the appropriate zval by sequentially searching the list.

In order to better test this behavior, we extend the test responder to
print the size of the upload, and patch the existing tests accordingly.
@cmb69
Copy link
Member Author

cmb69 commented Jan 22, 2020

If there are no objections, I'll merge this PR in a week (and will re-classify bug 79013 as doc issue; IOW, stick with the chunked upload).

@cmb69
Copy link
Member Author

cmb69 commented Jan 24, 2020

An update regarding https://bugs.php.net: whether libcurl uses chunked transfer encoding obviously depends on the HTTP version (and maybe other factors), so I don't think it's up to us to document this.

cmb69 added 2 commits February 2, 2020 15:53
According to the `curl_mime_data_cb()` man page[1], the seek callback
is only called when resending due to redirection.  In this case the
stream would already have been opened, so there is no need to try to
open the stream in `seek_cb()`.

[1] <https://curl.haxx.se/libcurl/c/curl_mime_data_cb.html>
@cmb69
Copy link
Member Author

cmb69 commented Feb 4, 2020

Thanks! Applied as 2d0dec9.

@cmb69 cmb69 closed this Feb 4, 2020
@cmb69 cmb69 deleted the cmb/fix-79019 branch February 4, 2020 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants