HTTP POST with HttpWebRequest

I am trying to POST some data as if I were using FORM on an HTML site (ContentType = multipart / form-data). The goal is Amazon s3. I use HttpWebRequest / HttpWebResponse and it all seems fine to me, but I still can’t deal with one problem, I keep getting the error:

<?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> 

seems self-describing, but I'm really sending the file field. I was able to send the file without problems through the test website, all the post data seems to be exactly the same. When I "spied" the request through wirehark all the headers and mail data, and also - it is there, as expected.

Does anyone have any ideas why amazon cannot see the file field?

Code used

(it's shortened a bit to make it more readable):

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

send data that goes to the stream:

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

and ... list of wires:

 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 

the only difference between the above report and the one obtained when downloading based on web applications is that the web application has fewer [TCP segments of reassembled PDUs] and has some [TCP Dup ACK 156 # 1] http> 58364 [ACK] Sq = 1 Ack = 7017 Win = 11668 Len = 0 entries (if it can be useful, I can send complete traces).

+1
source share
3 answers

solved! the border was wrong - you need to add 2 more hyphens for post data than the value in the header. what needed to be done in the above code:

 string boundary = "---------------------------317205771417341028"; request.ContentType = "multipart/form-data; boundary=" + boundary; 

[...]

 using (Stream s = request.GetRequestStream()) { boundary = "--" + boundary "\n"; 

[...] so easy ... and yet so annoying ...

+1
source

POST that on your own server, not Amazon, and then check POST - I will bet that your headers are set incorrectly, which means that since you use multipart form-data, POST cannot be decoded.

In any case, you should use the official SDK.

http://aws.amazon.com/sdkfornet/

0
source

I spent about three days in a row trying to solve the same problem. Make sure you use consistent line endings for your POST body format. I forgot about one carriage return ( \r ) in the CRLF sequence, and Amazon S3 gave me this error and similar ones.

0
source

All Articles