POST文件上传适用于curl但不适用于Qt(seafile web api)

时间:2014-06-02 14:02:58

标签: c++ qt http curl network-programming

我尝试使用seafile web api(https://github.com/haiwen/seafile/wiki/Seafile-web-API#upload-file)从c ++ Qt5代码上传文件。

API与curl配合得很好,但是对于Qt,我得到了一个" 400 Bad Request"来自阿帕奇。

我使用wireshark来查看请求中的差异。卷曲:

curl -k -F "file=@/tmp/test_up.txt; filename=qt.txt" -F parent_dir=/ myserver.com/seafhttp/upload-api/f8e70ecc

给了我

POST /seafhttp/upload-api/f8e70ecc HTTP/1.1
User-Agent: curl/7.37.0
Host: myserver.com
Accept: */*
Content-Length: 292
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------9a2b257b2a34c31f

--------------------------9a2b257b2a34c31f
Content-Disposition: form-data; name="file"; filename="qt.txt"
Content-Type: text/plain

test up

--------------------------9a2b257b2a34c31f
Content-Disposition: form-data; name="parent_dir"

/
--------------------------9a2b257b2a34c31f--

现在是Qt来源:

QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

QHttpPart file_part;
file_part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\"; filename=\"qt.txt\"")); //
file_part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
QFile *file = new QFile{"/tmp/test_up.txt"};
file->open(QIODevice::ReadOnly);
file_part.setBodyDevice(file);
file->setParent(multipart); // we cannot delete the file now, so delete it with the multipart

QHttpPart parent_dir_part;
parent_dir_part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"parent_dir\""));
parent_dir_part.setBody("/");

multipart->append(file_part);
multipart->append(parent_dir_part);

QNetworkRequest request{server + upload_url};
_reply = _manager.post(request, multipart);
multipart->setParent(_reply); // delete the multipart with the reply

给了我

POST /seafhttp/upload-api/f8e70ecc HTTP/1.1
Content-Type: multipart/form-data; boundary="boundary_.oOo._MTgzMTcwMjYyNg==MTc3NDExNzExNg==NTI2MDQyOTI1"
MIME-Version: 1.0
Content-Length: 349
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Accept-Language: fr-FR,en,*
User-Agent: Mozilla/5.0
Host: myserver.com

--boundary_.oOo._MTgzMTcwMjYyNg==MTc3NDExNzExNg==NTI2MDQyOTI1
Content-Disposition: form-data; name="file"; filename="qt.txt"
Content-Type: text/plain

test up

--boundary_.oOo._MTgzMTcwMjYyNg==MTc3NDExNzExNg==NTI2MDQyOTI1
Content-Disposition: form-data; name="parent_dir"

/
--boundary_.oOo._MTgzMTcwMjYyNg==MTc3NDExNzExNg==NTI2MDQyOTI1--

服务器端我有两个请求的这些日志:

myserver.com - - [02/Jun/2014:15:20:18 +0200] "POST /seafhttp/upload-api/f8e70ecc HTTP/1.1" 200 166 "-" "curl/7.37.0"
myserver.com - - [02/Jun/2014:15:21:28 +0200] "POST /seafhttp/upload-api/f8e70ecc HTTP/1.1" 400 103 "-" "Mozilla/5.0"

现在这两个请求似乎非常接近,我在Qt代码中没有使用任何花哨的东西,遵循QHttpMultiPart文档示例。 我尝试更改UserAgent或边界以更接近卷曲,但没有成功。

我在流量中评论的一个区别是,当我使用curl时,它会等待"继续"在发送其余数据之前:

[TCP segment of a reassembled PDU]
[ACK]
HTTP/1.1 100 Continue
[ACK]
[TCP segment of a reassembled PDU]
[ACK]
POST /seafhttp/upload-api/f8e70ecc HTTP/1.1  (text/plain)
[ACK]
HTTP/1.1 100 Continue
HTTP/1.1 200 OK

而Qt则是这样的:

[TCP segment of a reassembled PDU]
[ACK]
POST /seafhttp/upload-api/f8e70ecc HTTP/1.1  (text/plain)
[ACK]
HTTP/1.1 400 Bad Request

这不是我的主要域名,所以我不确定我可以做些什么来进一步调试

任何提示都表示赞赏,谢谢

1 个答案:

答案 0 :(得分:0)

确定手动重写请求后直到它工作我找到了解决方案。这似乎是一个错误服务器端

Qt在标题中的边界声明周围添加双引号,这似乎与rfc有关(请参阅此处的封闭错误:https://bugreports.qt-project.org/browse/QTBUG-29744)。

无论如何,解决方法很简单,我只是重写了没有引号的标题:

request.setRawHeader("Content-Type", "multipart/form-data; boundary=" + multipart->boundary());