134

I'm working on an iPhone app that makes a multipart HTTP request with multiple image files.

It looks like what's happening, on the server side, is that one of the images is getting parsed properly, but the other two files are not.

Can anybody post a sample HTTP multipart request that contains multiple image files?

0

2 Answers 2

207

Well, note that the request contains binary data, so I'm not posting the request as such - instead, I've converted every non-printable-ascii character into a dot (".").

POST /cgi-bin/qtest HTTP/1.1 Host: aram User-Agent: Mozilla/5.0 Gecko/2009042316 Firefox/3.0.10 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://aram/~martind/banner.htm Content-Type: multipart/form-data; boundary=2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Length: 514 --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Disposition: form-data; name="datafile1"; filename="r.gif" Content-Type: image/gif GIF87a.............,...........D..; --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Disposition: form-data; name="datafile2"; filename="g.gif" Content-Type: image/gif GIF87a.............,...........D..; --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f Content-Disposition: form-data; name="datafile3"; filename="b.gif" Content-Type: image/gif GIF87a.............,...........D..; --2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f-- 

Note that every line (including the last one) is terminated by a \r\n sequence.

Sign up to request clarification or add additional context in comments.

10 Comments

just to avoid any confusion: notice that before each boundary string in the content there are two extra dashes --<boundary>. For the last line is --<boundary>--
@turkeyhundt - two options come to mind immediately: 1) write your loop as (print boundary, print stuff), and then after the for loop completes follow that with (print boundary with extra dashes). That's probably the easiest way. 2) write your for() loop to run whatever index variable you have down to 0, instead of up from 0. Then add an extra two dashes when you print the boundary at the end if the index variable is 0.
This is really NOT a good example. Why would you choose a boundary that already has -- in it for an example. If someone doesn't know that that boundary is the again prefixed with another 2 -- you're screwed.
This is though exactly what my web browser produced at the time. Real browsers use boundaries with many dashes in them.
Yes, browsers put dashes in the boundaries. Better people find out in this answer than later.
|
73

EDIT: I am maintaining a similar, but more in-depth answer at: https://stackoverflow.com/a/28380690/895245

To see exactly what is happening, use nc -l and a user agent like a browser or cURL.

Save the form to an .html file:

<form action="http://localhost:8000" method="post" enctype="multipart/form-data"> <p><input type="text" name="text" value="text default"> <p><input type="file" name="file1"> <p><input type="file" name="file2"> <p><button type="submit">Submit</button> </form> 

Create files to upload:

echo 'Content of a.txt.' > a.txt echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html 

Run:

nc -l localhost 8000 

Open the HTML on your browser, select the files and click on submit and check the terminal.

nc prints the request received. Firefox sent:

POST / HTTP/1.1 Host: localhost:8000 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET Connection: keep-alive Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266 Content-Length: 554 -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="text" text default -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="file1"; filename="a.txt" Content-Type: text/plain Content of a.txt. -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="file2"; filename="a.html" Content-Type: text/html <!DOCTYPE html><title>Content of a.html.</title> -----------------------------9051914041544843365972754266-- 

Aternativelly, cURL should send the same POST request as your a browser form:

nc -l localhost 8000 curl -F "text=default" -F "[email protected]" -F "[email protected]" localhost:8000 

You can do multiple tests with:

while true; do printf '' | nc -l localhost 8000; done 

2 Comments

Thank you for the great post. How do you compute the content length? Is is the length of all the contents of contents (e.g. just "text default") or including the descriptions (from ---90xx66 until --90xx66--)?
@mojovski I think it counts everything, but not 100% sure. Try a minimal example on your own browser with this technique + wc to check it out + try to read the HTTP standard ;-) I think copy paste from stack overflow + xsel -b | wc does not match up because servers reply with \r\n at the end of each line, but those were converted to just \n at some point. Ping me if you conclude anything.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.