user826955 user826955 - 3 months ago 28
C++ Question

Use libcurl to upload a file

I am trying to access a website using

libcurl
, and post to a form including a file upload. I am not 100% sure what I am doing, since I am basically reverse engineering the website using chrome developer tools & analyzing POST/GET calls, which I will then replicate using
libcurl
.

So basically I am accesing some sort of forum, where one can post messages, which can have an attachment. My program can already login, read messages, and post text messages using POST to the above mentioned form just fine. The only thing which is not working, is posting a message PLUS file attachment.

According to chrome developer tools, I can only see a POST to the same form, including some more parameters (file name, flag for file upload) when I upload a file using the browser. However, I cannot see any indication of a file upload in chrome developer tools, so I have no hint on how to do it programatically.

Basically, what I am just trying to do, is using the same POST using
libcurl
which I can successfully use to post non-attachment messages, but


  • I'll include the extra post-parameters

  • supply a read-function to
    libcurl

  • tell
    libcurl
    to upload (
    CURLOPT_UPLOAD
    )

  • supply
    CURLOPT_INFILESIZE

  • I also tried to additionally supply
    CURLOPT_POST



Now, a succesful POST (withouth attachment) will always redirect to the overview, thus HTTP 302 indicates a successful operation.

As soon as I try to upload using the code above, however, I will only get HTTP 200 and the message is not send. Yet I can see that my read function is called, and that all bytes of the file are transferred.

Interestingly enough, when I omit
CURLOPT_UPLOAD
, I can see that my read-function is not called (thus no file is transferred), and the POST will get a HTTP 302 as reply, and the message is actually posted. However, when you view it, it contains a hint "attachment was deleted".

I know all this is pretty much very special to the website I am trying to access, and probably no one can exactly know what the server is expecting. But could anyone give me some hints of what might be going wrong, or what typically could be causing this?

Does anyone maybe know some dummy-site, which I could at least use to test my general POST/upload feature, to verify my
libcurl
usage is correct?

Any hints/tips greatly appreciated :)




- Update march 12th:




As suggested by daniel stenberg, I am trying to use multipart/formpost uploads now, but still with no success. This is what the verbose output is giving me:

16/03/12 23:21:04 [HTTP] POST http://www.some.url // printed by my lib
* Found bundle for host www.some.url: 0x154f53460
* Re-using existing connection! (#1) with host www.some.url
* Connected to www.some.url (someipaddress) port 80 (#1)
> POST /some/path/ HTTP/1.1

Host: www.some.url
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:22.0) Gecko/20100101 Firefox/22.0
Accept: */*
Cookie: FUP_sid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; FUP_vid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; FUPautologin=cb8c3ef4fcdecc390f6eca3f37814f623431219
Content-Length: 170627
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------1b0a4317b11b7518

< HTTP/1.1 100 Continue


few seconds pause / uploading here

< HTTP/1.1 302 Found
< Date: Sat, 12 Mar 2016 22:21:04 GMT
< Server: Apache
< Cache-Control: private, proxy-revalidate, s-maxage=0, no-cache
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
< Location: http://www.some.url/some/path/redirect/
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=UTF-8
* HTTP error before end of send, stop sending
<
* Closing connection 1
16/03/12 23:21:06 [HTTP] DONE (0/302) // printed by my lib, http code of last operation


I can use the same
libcurl
code to successfully upload files to posttestserver.com, so I am unsure what the problem is. What confuses me the most is the
* HTTP error before end of send, stop sending
statement. It seems like the server is somehow aborting/refusing the upload. On the website I can see my submitted message with the hint that the uploaded file was removed (or never fully uploaded?).

Could it maybe be that
libcurl
is confused by the 302 response from the server (which is the normal response for new message submissions, since it redirects to the message overview), or what could be the issue?

Please help :(

This is my code:

struct curl_httppost* postForm = NULL;
struct curl_httppost* last = NULL;

for (HtmlInput* param= form->getFirstParameter(); param;
param= form->getNextParameter())
{
HtmlElement::Attribute* nameAtt= param->getAttribute("name");
HtmlElement::Attribute* valueAtt= param->getAttribute("value");

curl_formadd(&postForm, &last,
CURLFORM_COPYNAME, notNull(nameAtt ? nameAtt->value.c_str() : 0),
CURLFORM_COPYCONTENTS, notNull(valueAtt ? valueAtt->value.c_str() : 0),
CURLFORM_END);
}

if (attachment)
{
curl_formadd(&postForm, &last,
CURLFORM_COPYNAME, "name",
CURLFORM_BUFFER, attachmentName ? attachmentName : "fileupload",
CURLFORM_BUFFERPTR, uploadBuffer.buffer,
CURLFORM_BUFFERLENGTH, uploadBuffer.size,
CURLFORM_CONTENTTYPE, contentType,
CURLFORM_END);
}

curl_easy_setopt(session, CURLOPT_URL, url);
curl_easy_setopt(session, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(session, CURLOPT_VERBOSE, 1L);

CURLcode curlCode= curl_easy_perform(session);

Answer

Nevermind, I figured I was sending wrong content in the multipart formdata. After adding debug output with CURLOPT_DEBUGFUNCTION and double checking and comparing the output with chrome's output, I found that the filename parameter was having a wrong name compared to the browser call.
After fixing this, my upload was working. So my implementation above is working and correct :)