views:

763

answers:

2

Hi guys,

I'm trying to upload a file and a send along a few parameters to my site using .NET / C#. Having read a few tutorials that do either a few parameters or a file, I've tried, unsuccessfully, to combine them. Here is how I try doing it:

WebRequest req = WebRequest.Create(baseURL + "upload");
req.Credentials = new NetworkCredential(username, password);
String boundary = "B0unD-Ary";
req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";
((HttpWebRequest)req).UserAgent = "UploadTester v0.1";

string postData = "--" + boundary + "\nContent-Disposition: form-data\n";
postData += "myId=123&someFk=456";
postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\" Content-Type: application/pdf\n\n";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);

byte[] filedata = null;
using (BinaryReader reader = new BinaryReader(File.OpenRead("myfile.pdf")))
    filedata = reader.ReadBytes((int)reader.BaseStream.Length);

req.ContentLength = byteArray.Length + filedata.Length;
req.GetRequestStream().Write(byteArray, 0, byteArray.Length);
req.GetRequestStream().Write(filedata, 0, filedata.Length);

WebResponse response = req.GetResponse();
Stream data = response.GetResponseStream();
StreamReader sReader = new StreamReader(data);
String sResponse = sReader.ReadToEnd();
response.Close();

When I execute it, I get a 500 exception, saying "Header section has more than 10240 bnytes (maybe it is not properly terminated)" and Wireshark informs me that the request sent was a malformed package, where the MIME multipart was malformed.

There are probably several issues here, so please let me know all the problems you can spot

Update: to separate MIME from C#/.NET, I've spawned a thread here: http://stackoverflow.com/questions/1880002/error-in-mime-packet-for-http-post

Update 2: So the backend indeed has issues with the content-length, saying that the amount of bytes available for reading is smaller than the stated content-length. BUT! If I reduce the content-length in req.ContentLength accordingly, I don't have a buffer size large enough for sending the data. Any suggestions?

Update 3: Actually, it looks like the header has a too large size compared to how much data it contains

Cheers

Nik

+1  A: 

I guess the immediate problem is a mismatch between the declared and the actual length.

Where did you miscalculated I am not sure but if I remember correctly the length should include every byte of the response (including headers) except for the first line.

To be sure I would build a simple html page to generate the post you want and examined the post with fiddler (or firebug)

mfeingold
Ah, thanks, that's a good hint. It's a pity that I have to do this by hand. I'm sure thousands of people have written code pretty much like this, would be easier with a standard library.
niklassaers
Hmm, but my content length is properly set to 129597 bytes, not anywhere near 10240. :-I
niklassaers
Instead of writing to the request stream, I would write it to a filestream, and see how many bytes are there, and make sure that the content length matches.Or alternately, write into a MemoryStream, then you can do a memoryStream.ToArra() and get the content length from that.
feroze
Does every part has to have its own content-length header? if not there will be no way to tell where a binary part ends
mfeingold
+2  A: 

The problem is that you're missing a '\n'. The following line:

string postData = "--" + boundary + "\nContent-Disposition: form-data\n";

should be:

string postData = "--" + boundary + "\nContent-Disposition: form-data\n\n";

And this line:

postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\" Content-Type: application/pdf\n\n"

is missing a '\n' before 'Content-Type'. It should be:

postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\"\nContent-Type: application/pdf\n\n"
Gonzalo
Thanks for pointing these out. After much 15 hours of debugging, I found the main problem: The .NET engine translates all my newlines to CR+Newline, thus writing more bytes than I have specified in the content-length. So, for anyone having a similar problem in the future: replace all newlines with CR + newline (\n to \r\n)
niklassaers