-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
curl_easy_perform() fails if a nested mime_handle was already used in a transfer #15842
Comments
Any chance you can provide an example code (in C) that shows this happening? Maybe by adjusting https://curl.se/libcurl/c/smtp-mime.html ? This way we would be sure we understand your issue exactly. |
I'm kind of embarassed to say that I'm not really fluent in C at all (wrapping libcurl has featured a steep learning curve for me, lol)... but I think I can get there since that mime example you kindly linked looks fairly complete and consists mainly of curl functions. It might be a couple days for my thick head to figure out the compiler process. If I can't figure it out reasonably quickly I'll at least come back with the equivalent raw DLL calls in AHK, heavily commented so you can follow. |
yeah, you can probably start with a rough psedu-code style version and I can try to convert that for us and then we can take it step by step |
I apologize for taking so long, I had to tend to something. ^^; Anyways, the simplified instructions to replicate:
Notably, if we do everything the same except execute the first transfer, the now-only transfer will execute as normal. Using my class to partially intialize variables, I have written a lengthy breakdown of the functions I've invoked to get to the error: Using that script, my class' error handling function captured the following info:
Finally, for sake of completion, here is the returned body from that script's first transfer to demonstrate that the mime functions are working as expected under most circumstances.
Assuming it's not user error on my part, I do think this "locking" could be intended behavior, if for no other reason than the way mime_handles are tightly integrated with their respective easy_handles. It's not really a problem that subparting previously used mime_handles creates a failure, I was just suprised since I didn't see it in the documentation. If this is indeed a bug, then I think a check (+appropriate error code) at the curl_mime_subparts function would be a good idea. |
This comment was marked as outdated.
This comment was marked as outdated.
Just to make sure I'm grokking things correctly:
If my limited C managed to understand that correctly, then yep, that looks good! (Now here is the part where you tell me it works on your end, haha. ^^; ) |
Your understanding of the code seems correct, yes. When I run this, I get a CURLcode rc = curl_mime_subparts(part2, mime1); 43 means Is this perhaps the problem you see as well? It seems to come from here: I'll take a deeper look. |
I think this minor tweak reproduces the original report: #include <stdio.h>
#include <curl/curl.h>
/* write callback that does nothing */
size_t write_it(char *ptr, size_t size, size_t nmemb, void *userdata)
{
return size * nmemb;
}
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
curl_mime *mime1;
curl_mimepart *part1;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_it);
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/");
mime1 = curl_mime_init(curl);
part1 = curl_mime_addpart(mime1);
curl_mime_data(part1, "<title>hello</title>", CURL_ZERO_TERMINATED);
curl_mime_type(part1, "text/html");
curl_mime_name(part1, "data");
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime1);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* Perform the request, res gets the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() 1 failed: %s\n",
curl_easy_strerror(res));
/* phase two, create a mime struct using the mime1 handle */
{
curl_mime *mime2 = curl_mime_init(curl);
curl_mimepart *part2 = curl_mime_addpart(mime2);
/* use the new mime setup */
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime2);
CURLcode rc = curl_mime_subparts(part2, mime1);
printf("rc = %d\n", (int)rc);
/* Perform the request, res gets the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() 2 failed: %s\n",
curl_easy_strerror(res));
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
} |
/cc @monnerat for info. There seems to be some state that is not reset properly when the same mime part is used again like this. The problem is easily reproducible but I have yet to find the exact culprit. |
Good, seems we're communicating effectively then. :D
I apologize I didn't catch the difference at a glance, but at least you caught it yourself pretty quickly. A thought had occurred to me earlier that the error might have been something relating to the DLL interface, like maybe Windows was butchering a buffer or whatever. That you were able to reproduce the issue without using a DLL cancels that idea, though, which is good since that would likely be harder to troubleshoot. Now that you've been able to reproduce the bug on your end I think that my usefulness to the conversation has ended. If there's anything more you need from me (to test a fixed build, perhaps) by all means ask! ^_^ |
Yes, I'll get back. Just need some time to get to the bottom of this while juggling some other things at the same time. |
First, you can reassign mime handle 1 because you still own it after using it within a Next, I don't think you reproduced the initial error, which has code 26 (caused by a premature EOF). |
Yes I do. Try the last code snippet I show you here a few comments up and you should see a 26.
My example reproduces it and we know how they are initialized! |
Sorry, I did not realized code erroring 43 was not the one listed. |
Nah, that was a bit unclear on my behalf. My first one was not doing the same thing, the second one does. |
My code example can also, exactly as @Qriist mentioned, be modified so that the first transfer is skipped and then magically the second transfer works (which then is the only transfer of course). Indicating that it is the transfer itself and use of the mime data that somehow makes the second use of it break. |
Here's a third version of mime-15842.c that also has a debug callback to display the sent formpost data. |
No rush at all! :)
No, I was definitely using the non-callback version, That said, I just tested On a lark I also tried without adding any data to mime1 and it, too, failed. Literally just: init mime1 -> perform -> init mime2 -> subparts -> perform returns 26 One thing I noticed was that the easy handle error buffer string is reporting seemingly very high buffer sizes compared to the data passed. My error handler I posted above reported 226/426 bytes read, when I passed 26 total bytes (13 each for title/data), and the 168 byte binary file I attempted just now reported 316/766 bytes read. (The size discrepency could just be encoding, though.) |
Subparts may have been previouly used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Fixes curl#15842
Subparts may have been previously used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Fixes curl#15842
Subparts may have been previously used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Reported-by: Qriist on github Fixes curl#15842
I found the problem:
As a result, the first structure is not rewound. |
Subparts may have been previously used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Reported-by: Qriist on github Fixes curl#15842
Subparts may have been previously used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Reported-by: Qriist on github Fixes curl#15842
Subparts may have been previously used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Reported-by: Qriist on github Fixes curl#15842
Subparts may have been previously used as a top-level mime structure and thus not rewound. New test 695 checks the proper functioning in these particular conditions. Reported-by: Qriist on github Fixes curl#15842
@Qriist are you able to try out the PR against your case to check if it fixes your problem the same way it fixed my reproducer? If so, then we can wait for your confirmation before we proceed. |
I use vcpkg to build since it basically automates the process, but I'll try to manually build the PR later tonight after work. I'll let you know if I'm successful, and if the successful build solves the problem. Also, side note, thank you very much for your patience with my C inexperience! |
I return to report confusing mixed results: I managed to get a seemingly succesful build with mingw following the indepth instructions from the curl.dev site, but the output dll contained no functions whatsoever. I went about it in this order:
Some quick internet searching suggests OpenSSL is incorrectly configured within the MSYS2 enviornment so I tried bypassing I'm kind of lost on where to go from here. |
I wouldn't know either. Getting things built and used on Windows goes beyond what I know. I do however believe that the fix is correct so I will go ahead and merge that and close this issue as fixed. If you, after getting this fix tested, find that there is something left to fix, this bug or something else, then feel free to create a new issue. |
I did this
To clarify on the title, nesting a
mime_handle
viacurl_mime_subparts()
technically works (returns 0) but the subsequentcurl_easy_perform()
fails.Bascially, In the process of writing a usage example, I discovered that I cannot use a
mime_handle
if that handle had a newly nestedmime_part
that had previously been used in acurl_easy_perform()
(and presumably incurl_multi_perform()
as well but I didn't test).Attempting to
perform
under this condition would always returnCURLE_READ_ERROR (26)
. As I can freely reuse themime_handle
in other ways and embed it as a subpart if freshly made, this seems to suggest something internal to curl.I recognize that this may be intended behavior, but I didn't see a note about it on the documentation so I figured I'd raise the flag. If it's intended please feel free to close the ticket. :)
I expected the following
to add the
mime_handle
as amime_part
curl/libcurl version
custom built libcurl from vcpkg with all supported features enabled:
libcurl/8.11.1-DEV wolfSSL/5.7.4 (GnuTLS/3.8.7) (mbedTLS/3.6.1) (LibreSSL/4.0.0) (Schannel) zlib/1.3.1 brotli/1.1.0 zstd/1.5.6 c-ares/1.34.3 WinIDN libpsl/0.21.5 libssh2/1.11.1_DEV nghttp2/1.64.0
operating system
Win10
The text was updated successfully, but these errors were encountered: