使用 libcurl 上传文件

Use libcurl to upload a file

我正在尝试使用 libcurl 和 post 访问一个包含文件上传的表单。我不是 100% 确定我在做什么,因为我基本上是使用 chrome 开发人员工具对网站进行逆向工程并分析 POST/GET 调用,然后我将使用 libcurl.[= 复制它26=]

所以基本上我正在访问某种论坛,在那里可以 post 可以有附件的消息。我的程序已经可以使用 POST 以上述形式登录、阅读消息和 post 短信。唯一不起作用的是 post 发送消息和文件附件。

根据chrome开发者工具,当我使用浏览器。但是,我在 chrome 开发人员工具 中看不到任何关于文件上传的指示,因此我没有关于如何以编程方式执行此操作的提示。

基本上,我只是想做的是使用相同的 POST 使用 libcurl 我可以成功地用于 post 非附件消息,但是

现在,成功的 POST(没有附件)将始终重定向到概览,因此 HTTP 302 表示操作成功。
然而,一旦我尝试使用上面的代码上传,我只会收到 HTTP 200 并且消息是 not 发送。但是我可以看到调用了我的读取函数,并且传输了文件的所有字节。

有趣的是,当我省略 CURLOPT_UPLOAD 时,我可以看到我的读取函数 未被调用 (因此没有文件被传输),并且 POST 将收到 HTTP 302 作为回复,消息实际上是 posted。但是,当您查看它时,它包含一个提示 "attachment was deleted".

我知道这一切对于我尝试访问的网站来说非常特别,可能没有人能确切地知道服务器期望什么。但是谁能给我一些提示,告诉我可能出了什么问题,或者通常是什么原因造成的?
有没有人知道一些虚拟站点,我至少可以用它来测试我的一般 POST/upload 功能,以验证我的 libcurl 用法是否正确?

任何 hints/tips 非常感谢:)


- 3 月 12 日更新:


根据 daniel stenberg 的建议,我现在尝试使用 multipart/formpost 上传,但仍然没有成功。这就是详细输出给我的内容:

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

几秒暂停/上传这里

< 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

我可以使用相同的 libcurl 代码将文件成功上传到 posttestserver.com,所以我不确定是什么问题。最让我困惑的是 * HTTP error before end of send, stop sending 语句。似乎服务器以某种方式 aborting/refusing 上传。在网站上,我可以看到我提交的消息,提示上传的文件已被删除(或从未完全上传?)。

会不会是 libcurl 被服务器的 302 响应弄糊涂了(这是 正常 新消息提交的响应,因为它重定向到消息概述),或者可能是什么问题?

请帮忙:(

这是我的代码:

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);

没关系,我想我在多部分表单数据中发送了错误的内容。在使用 CURLOPT_DEBUGFUNCTION 添加调试输出并仔细检查并将输出与 chrome 的输出进行比较后,我发现文件名参数与浏览器调用相比有一个错误的名称。
修复此问题后,我的上传工作正常。所以我上面的实现是正确的:)