Я пытаюсь разместить некоторые данные, как если бы я использовал FORM на сайте HTML (ContentType = multipart / form-data). Цель - амазонка s3.
Я использую HttpWebRequest / HttpWebResponse и мне все вроде нормально, но я все еще не могу решить одну проблему, я получаю сообщение об ошибке:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>POST requires exactly one file upload per request.</Message>
<ArgumentValue>0</ArgumentValue>
<ArgumentName>file</ArgumentName>
</Error>
кажется, что это самоописание, но я действительно отправляю поле "файл". Мне удалось без проблем отправить файл через тестовый веб-сайт, все пост-данные выглядят точно так же.
Когда я «шпионю» за запрос через wireshark, все заголовки и почтовые данные - это там, как и ожидалось.
У кого-нибудь есть идеи, почему амазонка не видит поле "файл"?
используемый код (он немного обрезан, чтобы сделать его более читабельным):
private void addStringToStream(string buff, Stream s)
{
var bytes = Encoding.UTF8.GetBytes(buff);
s.Write(bytes, 0, bytes.Length);
counter += bytes.Length;
}
private void doPost()
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "POST";
request.ProtocolVersion = new Version(1, 1);
request.KeepAlive = true;
request.AllowAutoRedirect = true;
request.Headers.Add("Accept-Language", "en-us,en;q=0.5");
request.Headers.Add("Accept-Encoding", "gzip,deflate");
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
request.Accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.10) Gecko/20071115 Firefox/2.0.0.10";
string boundary = "---------------------------317205771417341028";
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.SendChunked = false;
request.Credentials = CredentialCache.DefaultCredentials;
request.CookieContainer = new CookieContainer();
request.ContentLength = calculateLength();
using (Stream s = request.GetRequestStream())
{
boundary += "\n";
string inLineContentH = "Content-Disposition: form-data; name=\"{0}\"";
string contentH = "Content-Disposition: form-data; name=\"{0}\"" + "\n" + "\n";
string keyH = "key";
string aclH = "acl";
string aclV = "public-read";
string accessKeyH = "AWSAccessKeyId";
string accessKeyV = publicKey;
string policyH = "policy";
string policyV = this.generatePolicy();
string signatureH = "signature";
string signatureV = generateSignature(policyV);
string fileH = "file";
string fileContentNameH = "filename=\"{0}\"";
string contentType2H = "Content-Type: application/octet-stream";
buff = boundary;
addStringToStream(buff, s);
buff = string.Format(contentH, keyH);
addStringToStream(buff, s);
buff = keyV + "\n";
addStringToStream(buff, s);
/* here are all of the others necessary fields added to stream just as the one above
no other operations are used, just adding bytes to stream
and finally we get to the file: */
buff = boundary;
addStringToStream(buff, s);
buff = string.Format(inLineContentH, fileH) + "; " + string.Format(fileContentNameH, Path.GetFileName(this.FilePath)) + "\n";
addStringToStream(buff, s);
buff = contentType2H + "\n" + "\n";
addStringToStream(buff, s);
var inStream = File.OpenRead(FilePath);
int val;
while ((val = inStream.ReadByte()) != -1)
{
s.WriteByte((byte)val);
counter++;
}
buff = "\n";
addStringToStream(buff, s);
buff = boundary;
addStringToStream(buff, s);
buff = string.Format(contentH, "submit");
addStringToStream(buff, s);
buff = "Upload to Amazon S3" + "\n";
addStringToStream(buff, s);
buff = boundary.Replace("\r", "").Replace("\n", "") + "--";
addStringToStream(buff, s);
}
request.GetResponse();
}
публиковать данные, поступающие в поток:
---------------------------317205771417341028
Content-Disposition: form-data; name="key"
webtest/image.png
---------------------------317205771417341028
Content-Disposition: form-data; name="acl"
public-read
---------------------------317205771417341028
Content-Disposition: form-data; name="AWSAccessKeyId"
AKIAJOQLTUC5H2NJ65NA
---------------------------317205771417341028
Content-Disposition: form-data; name="policy"
Oi8vd3d3Lmdvb2dsZS[...]c3QiXSwNCiAgXQ0KfQ0K
---------------------------317205771417341028
Content-Disposition: form-data; name="Signature"
06GBK5DJ71aB[...]M8Ct8JOE=
---------------------------317205771417341028
Content-Disposition: form-data; name="file"; filename="eclipse.png"
Content-Type: application/octet-stream
‰PNG
IHDRn
[...the rest of the image...]
IEND®B‚
---------------------------317205771417341028
Content-Disposition: form-data; name="submit"
Upload to Amazon S3
---------------------------317205771417341028--
и ... список проволочной акулы:
OUT TCP 58383 > http [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=2 SACK_PERM=1
IN TCP http > 58383 [SYN, ACK] Seq=0 Ack=1 Win=8190 Len=0 MSS=1460 WS=6 SACK_PERM=1
OUT TCP 58383 > http [ACK] Seq=1 Ack=1 Win=65700 Len=0
OUT TCP [TCP segment of a reassembled PDU]
IN HTTP HTTP/1.1 100 Continue
OUT TCP [TCP segment of a reassembled PDU]
OUT TCP [TCP segment of a reassembled PDU]
OUT TCP [TCP segment of a reassembled PDU]
OUT TCP [TCP segment of a reassembled PDU]
IN TCP http > 58383 [ACK] Seq=26 Ack=2031 Win=1331456 Len=0
OUT TCP [TCP segment of a reassembled PDU]
OUT TCP [TCP segment of a reassembled PDU]
IN TCP http > 58383 [ACK] Seq=26 Ack=3969 Win=1337344 Len=0
OUT TCP [TCP segment of a reassembled PDU]
OUT TCP [TCP segment of a reassembled PDU]
IN TCP http > 58383 [ACK] Seq=26 Ack=6889 Win=1343232 Len=0
OUT TCP [TCP segment of a reassembled PDU]
OUT TCP [TCP segment of a reassembled PDU]
IN TCP http > 58383 [ACK] Seq=26 Ack=8441 Win=1346048 Len=0
OUT HTTP POST / HTTP/1.1
//the one above contains the last bytes added to the stream
IN TCP http > 58383 [ACK] Seq=26 Ack=10225 Win=1348864 Len=0
IN TCP http > 58383 [ACK] Seq=26 Ack=10857 Win=1351936 Len=0
IN TCP http > 58383 [ACK] Seq=26 Ack=12162 Win=1354752 Len=0
IN TCP http > 58383 [ACK] Seq=26 Ack=13622 Win=1357824 Len=0
IN TCP http > 58383 [ACK] Seq=26 Ack=13913 Win=1360640 Len=0
IN TCP [TCP segment of a reassembled PDU]
IN HTTP/XML HTTP/1.1 400 Bad Request
//the one above includes the error info quoted in the beginning
IN TCP http > 58383 [FIN, ACK] Seq=649 Ack=13913 Win=1360640 Len=0
OUT TCP 58383 > http [ACK] Seq=13913 Ack=650 Win=65052 Len=0
OUT TCP 58383 > http [FIN, ACK] Seq=13913 Ack=650 Win=65052 Len=0
IN TCP http > 58383 [ACK] Seq=650 Ack=13914 Win=1360640 Len=0
единственное различие между отчетом выше и отчетом, созданным при загрузке на основе веб-приложения, состоит в том, что на основе веб-приложения меньше позиций [сегмента TCP повторно собранного PDU], а также есть [TCP Dup ACK 156 # 1] http> 58364 [ACK] Sq = 1 Ack = 7017 Win = 11668 Len = 0 записей (если это может быть полезно, я могу отправить полные следы).