Why is form enctype=multipart/form-data required when uploading a file?

Solution 1:

It has to do with how the browser packages binary and form data for transmission over HTTP. By default only form data is sent, but if the form needs to support uploading a file, then the binary data must also be appended and separated from the form data.

Scott Hanselman gives a good explanation of this here:

HTTP and How File Upload works via HTTP

It's always better, for me, to understand WHY and HOW something is happening. If you say "just because" or "whatever, you just add that, and it works" then I think that's sad. For some reason while many folks understand FORM POSTs and generally how form data is passed up to the server, when a file is transferred many just conclude it's magic. Why do we have to add enctype="multipart/form=data" on our forms that include file uploads? Because the form will now be POSTed in multiple parts.

If you have a form like this:

<form action="/home/uploadfiles" method="post" enctype="multipart/form-data">
    <label for="file">Filename:</label>
    <input type="file" name="file" id="file" />
    <input type="submit" name="submit" value="Submit" />
</form>

The resulting Form POST will look like this (slightly simplified):

POST /home/uploadfiles HTTP/1.1
Content-Type: multipart/form-data; boundary=---------------------------7d81b516112482 
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64)
Content-Length: 324

-----------------------------7d81b516112482 
Content-Disposition: form-data; name="file"; filename="\\SERVER\Users\Scott\test.txt"
Content-Type: text/plain

foo
-----------------------------7d81b516112482
Content-Disposition: form-data; name="submit"

Submit
-----------------------------7d81b516112482--

Notice a few things about this POST. First, notice the content-type and boundary="" and how the boundary is used later, as exactly that, a boundary between the multiple parts. See how the first part shows that I uploaded a single file, of type text/plain. You can interpolate from this how you'd expect multiple files to show up if they were all POSTed at once.

And of course, look at how different this would look if it were just a basic form POST without the enctype="multipart/form=data" included:

POST /home/uploadfiles HTTP/1.1 
Content-Type: application/x-www-form-urlencoded
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64)
Content-Length: 13

submit=Submit

See how the content type is different? This is a regular, typical form POST. Perhaps atypical in that it includes only a Submit button! ....

As an aside, if you looked at an email of yours with multiple attached files, it would look VERY similar to the body of the first HTTP message as multipart MIME encoding is found everywhere, as is common with most good ideas.

Solution 2:

That is part of the specification for HTML File Upload as described in RFC-1867, which was the proposal to allow file uploads in HTML forms (circa 1995).

From section 2:

This proposal makes two changes to HTML:

1) Add a FILE option for the TYPE attribute of INPUT.
2) Allow an ACCEPT attribute for INPUT tag, which is a list of media types or type patterns allowed for the input.

In addition, it defines a new MIME media type, multipart/form-data, and specifies the behavior of HTML user agents when interpreting a
form with ENCTYPE="multipart/form-data" and/or <INPUT type="file">
tags.

When you set enctype to multipart/form-data, the browser separates each file or attachment in the upload with a "multipart boundary", which is a unique identifier that defines the beginning and end of each "part".

That allows the browser to send multiple parts (hence the name) in one request, and identify each one with its own metadata like mime type, file name, etc.