RFC 1867

Form-based File Upload in HTML

πŸ“… published November 1995, from ietf

RFC 1867 πŸ’– Form-based File Upload in HTML πŸŽ€

okay bestie, the title block is giving Network Working Group 🌸. The authors are E. Nebel and L. Masinter from Xerox Corporation πŸ’…, the category is Experimental πŸ§ͺ, and the date is November 1995 πŸ“…. The title block doesn't list anything this RFC obsoletes or updates. It's a whole proposal for letting web forms upload files πŸ“€βœ¨

Status of this Memo 🌈

This memo defines an Experimental Protocol for the Internet community πŸ§ͺ. It does not specify an Internet standard of any kind. Discussion and suggestions for improvement are requested πŸ’¬. Distribution of this memo is unlimited πŸ¦‹.

1. Abstract ✨

okay so HTML forms are already amazing for asking the user for info πŸ™Œ. But there was one big gap 😭: forms had no way to ask the user to send over a file πŸ“. Service providers who needed files ended up building their own custom user applications just to get them πŸ› οΈ. (Some examples of those custom browsers were posted on the www-talk mailing list πŸ’Œ.)

So this proposal extends HTML so information providers can ask for file uploads in a uniform way πŸŽ€. It also describes a MIME-compatible representation for the file upload responses πŸ“¦. And there's a backward compatibility strategy so new servers can still work with current HTML user agents 🫢. Not me being impressed by that last part πŸ”₯.

The proposal doesn't depend on which version of HTML it ends up being part of πŸ¦‹.

2. HTML forms with file submission πŸ’…

the current HTML spec gives the TYPE attribute of <INPUT> eight possible values: CHECKBOX, HIDDEN, IMAGE, PASSWORD, RADIO, RESET, SUBMIT, and TEXT πŸ“. It also sets the default ENCTYPE attribute of <FORM> when using the POST method to "application/x-www-form-urlencoded" πŸ“.

This proposal makes two changes to HTML πŸ’–:

  1. Add a FILE option for the TYPE attribute of <INPUT> πŸ“.
  2. Allow an ACCEPT attribute on the <INPUT> tag, which is a list of media types or type patterns allowed for the input 🎯.

It also defines a brand new MIME media type, multipart/form-data 🌟, and spells out how HTML user agents should behave when they see a form with ENCTYPE="multipart/form-data" and/or <INPUT type="file"> tags 🧚.

These changes could be looked at separately, but honestly they're all needed for file upload to be reasonable 🫢.

Say a form author wants to ask a user for one or more files. They'd write something like this πŸ’•:

<FORM ENCTYPE="multipart/form-data" ACTION="_URL_" METHOD=POST>

File to process: <INPUT NAME="userfile1" TYPE="file">

<INPUT TYPE="submit" VALUE="Send File">

</FORM>

For the DTD change 🧩, you just add one item to the entity InputType. And the INPUT tag gets an ACCEPT attribute, which is a list of comma-separated media types πŸ“‹.

  ... (other elements) ...

  <!ENTITY % InputType "(TEXT | PASSWORD | CHECKBOX |
                         RADIO | SUBMIT | RESET |
                         IMAGE | HIDDEN | FILE )">
  <!ELEMENT INPUT - 0 EMPTY>
  <!ATTLIST INPUT
          TYPE %InputType TEXT
          NAME CDATA #IMPLIED  -- required for all but submit and reset
          VALUE CDATA #IMPLIED
          SRC %URI #IMPLIED  -- for image inputs --
          CHECKED (CHECKED) #IMPLIED
          SIZE CDATA #IMPLIED  --like NUMBERS,
                                  but delimited with comma, not space
          MAXLENGTH NUMBER #IMPLIED
          ALIGN (top|middle|bottom) #IMPLIED
          ACCEPT CDATA #IMPLIED --list of content types
          >

  ... (other elements) ...

3. Suggested implementation πŸ› οΈ

user agents that read HTML get a lot of freedom to pick whatever mechanism fits their context πŸ¦‹. This section just suggests how one class of user agent, WWW browsers, could do file upload 🌐.

3.1 Display of FILE widget πŸ“‚

When the browser hits an <INPUT> tag of type FILE, it might show any file names that were already picked, plus a "Browse" button or some other way to select files πŸ”. Pressing "Browse" would send the browser into a file selection mode that fits the platform πŸ’». Window-based browsers might pop up a file selection window, for example ✨. In that dialog, the user could replace the current selection, add a new file, and so on 🧺. Implementers might also let the list of file names be edited by hand ✏️.

If an ACCEPT attribute is present, the browser might limit the file patterns it prompts for so they match the appropriate file extensions for the platform 🎯.

3.2 Action on submit πŸš€

When the user finishes the form and presses the SUBMIT element, the browser should send the form data and the contents of the selected files πŸ“€. The application/x-www-form-urlencoded encoding is inefficient for sending large amounts of binary data or text with non-ASCII characters 😩. So a new media type, multipart/form-data, is proposed as an efficient way to send the values from a filled-out form from client to server πŸ’–.

3.3 use of multipart/form-data 🧩

The definition of multipart/form-data shows up in section 7 πŸ”œ. A boundary gets picked that doesn't appear in any of the data πŸ™ˆ. (Sometimes that choice is made probabilistically 🎲.) Every field of the form gets sent in the order it appears in the form, as one part of the multipart stream 🌊. Each part identifies the INPUT name from the original HTML form 🏷️. Each part should be labelled with an appropriate content-type if the media type is known (for example, inferred from the file extension or the operating system's typing info) 🧠. If it isn't known, it gets labelled as application/octet-stream πŸ“¦.

If several files are selected, they should be transferred together using the multipart/mixed format πŸ—‚οΈ.

HTTP can carry arbitrary BINARY data πŸ’ͺ. But for mail transport (say, when the ACTION is a mailto: URL) the default encoding is 7BIT πŸ“§. If a part's value doesn't fit that default encoding, the value may need to be encoded and the content-transfer-encoding header supplied πŸ”. [See section 5 of RFC 1521 for more details.]

The original local file name can be supplied too πŸ“. You can put it in a filename parameter on the content-disposition: form-data header, or, when there are several files, in a content-disposition: file header on the subpart πŸŽ€. The client application should make its best effort to supply the file name πŸ’ͺ. If the client's operating system file name isn't US-ASCII, the name might be approximated, or encoded using the method of RFC 1522 🌍. This is handy when uploaded files reference each other, like a TeX file and its .sty auxiliary style description πŸ“œβœ¨.

On the server end, the ACTION might point to an HTTP URL that implements the form's action through CGI πŸ–₯️. In that case, the CGI program would notice that the content-type is multipart/form-data and parse the various fields πŸ”Ž. That includes checking they're valid and writing the file data to local files for later processing πŸ—ƒοΈ.

3.4 Interpretation of other attributes πŸŽ€

The VALUE attribute might be used with <INPUT TYPE=file> tags to set a default file name πŸ“. That's probably platform dependent πŸ–₯️. It could still be useful in a sequence of several transactions, for example so the user isn't asked for the same file name over and over 😀.

The SIZE attribute might be given as SIZE=width,height πŸ“. Here width is the default for file name width, and height is the expected size of the list of selected files πŸ“‹. This helps form designers who expect to get several files and want a multiline file input field in the browser, ideally with a "browse" button next to it 🌈. When no height is given (the designer expects just one file), the browser should show a one-line text field 🫧. When the height is greater than 1 (the designer expects multiple files), it should show a multiline text area with scrollbars πŸ“œπŸ’œ.

4. Backward compatibility issues πŸ”

It isn't required for this enhancement to the current WWW form mechanism to get adopted successfully πŸ™‚. Still, it's useful to plan a migration strategy πŸ—ΊοΈ. That way, people with older browsers can still take part in file upload dialogs by using a helper application 🧚.

Most current web browsers treat <INPUT TYPE=FILE> as <INPUT TYPE=TEXT> and give the user a text box πŸ“. The user can type a file name into that box πŸ™ƒ. Current browsers also seem to ignore the ENCTYPE parameter on <FORM> and always send the data as application/x-www-form-urlencoded πŸ™„.

So the server CGI can be written to notice when the returned form data has content-type application/x-www-form-urlencoded instead of multipart/form-data. From that it knows the user is on a browser that doesn't implement file upload πŸ•΅οΈβ€β™€οΈ.

In that situation, instead of replying with a text/html response, the CGI can send back a data stream that a helper application can process πŸ’Œ. This stream has the type application/x-please-send-files and contains:

  • The (fully qualified) URL to which the actual form data should be posted (terminated with CRLF)
  • The list of field names that were supposed to be file contents (space separated, terminated with CRLF)
  • The entire original application/x-www-form-urlencoded form data as originally sent from client to server.

In this case, the browser needs to be configured to handle application/x-please-send-files by launching a helper application πŸ”§.

The helper reads the form data and notes which fields held 'local file names' that need to be swapped out for their data content πŸ”„. It might also prompt the user to change or add to the list of files πŸ“‹. Then it repackages the data and file contents as multipart/form-data to send back to the server πŸ“¦.

The helper basically generates the kind of data a 'new' browser should have sent in the first place πŸ’…. The URL it goes to should match the original ACTION URL 🎯. The point is that the server can use the same CGI to handle both old and new browsers 🫢✨.

The helper doesn't need to display the form data πŸ™ˆ. But it should make sure the user actually gets prompted about whether it's okay to send the files requested 🚨. That's there to prevent a security problem with malicious servers asking for files the user never actually agreed to share 🫣. It would also be useful to show the status of the file transfer while it's happening πŸ“Š.

⚠️ Security note, babe: the prompt is the thing standing between the user and a malicious server quietly asking for files nobody promised to send. Don't skip it πŸ”πŸ’€.

5. Other considerations πŸ’…

(to be continued…) πŸ¦‹

5.1 Compression, encryption ✨

okay so this scheme doesn't deal with compressing files at all πŸ™ˆ After thinking it over, the optimization stuff for file compression felt way too complex to have browsers automatically decide when files should get compressed. Lots of link-layer transport mechanisms (like high-speed modems) already do data compression over the link, so optimizing for compression at that layer might not even be appropriate 🫢

It might be possible for browsers to optionally send a content-transfer-encoding of x-compress for file data, and for servers to decompress the data before processing if they want to. We just left that out of the proposal πŸ’…

Encryption isn't in here either πŸ” The proposal doesn't have a mechanism for encrypting the data. That should be handled by whatever other mechanisms are already in place for secure transmission of data, whether that's secure HTTP or mail πŸ’œ

5.2 Deferred file transmission πŸ¦‹

Sometimes it's a good idea for the server to check parts of the form data (like a user name or account) before it even gets ready to receive the data. But after thinking it through, we decided that servers who want this should build it as a series of forms instead. Some of the data that already got validated can be sent back to the client as 'hidden' fields, or the form can be arranged so the stuff that needs validating comes first. This puts the job of keeping track of a transaction's state only on servers building complex apps, while simple input stays simple πŸ‘‘

HTTP might require a content-length for the whole transmission. Even if it didn't, HTTP clients are encouraged to supply a content-length for the overall file input πŸ“ so a busy server can tell if the file is too big to process reasonably. Then it can just return an error code and close the connection without waiting for all the incoming data. Some current CGI implementations require a content-length in every POST transaction πŸ’€

If the INPUT tag includes the attribute MAXLENGTH, the user agent should consider its value to represent the maximum Content-Length (in bytes) that the server will accept for transferred files. That's how servers can hint to the client how much room they have for a file upload before the upload happens 🧚 Just know it's only a hint, because the server's actual requirements might change between when the form was created and when the file gets submitted πŸ™ˆ

Also, an HTTP server may abort a file upload in the middle of the transaction if the file being received is too large βœ‚οΈ

5.3 Other choices for return transmission of binary data 🌈

Various people have suggested using a new MIME top-level type called "aggregate", like aggregate/mixed, or a content-transfer-encoding of "packet", to express indeterminate-length binary data instead of relying on multipart-style boundaries. We're not opposed to that, but it would need additional design and standardization work to get "aggregate" accepted πŸ™ƒ Meanwhile, the multipart mechanisms are super established, simple to implement on both the sending client and the receiving server, and just as efficient as other methods of dealing with multiple combinations of binary data ✨

5.4 Not overloading <INPUT> πŸŽ€

Some people wondered if it's smart to overload 'INPUT' for this function instead of just making a totally different FORM element. Among other considerations, the migration strategy you're allowed to use with <INPUT> matters a lot πŸ‘€ Also, the <INPUT> field is already overloaded to hold most kinds of data input, so instead of making a bunch of new <INPUT> tags, it felt way more reasonable to enhance <INPUT> πŸ’…

The 'type' of INPUT isn't the content-type of what gets returned. It's the 'widget-type', aka the interaction style with the user. The description was carefully written so that <INPUT TYPE=FILE> works for text browsers or audio-markup too 🎧

5.5 Default content-type of field data πŸ’–

Lots of input fields in HTML are typed in by the user, and there was some ambiguity about how form data should be sent back to servers 🀷 Making the content-type of <INPUT> fields be text/plain clearly disambiguates that the client should properly encode the data before sending it back to the server, with CRLFs 🫢

5.6 Allow form ACTION to be "mailto:" πŸ“¬

Totally separate from this proposal, it would be super useful for HTML user agents to let a form's ACTION be a "mailto:" URL. It's a good idea with or without this proposal πŸ’Œ Similarly, the ACTION for an HTML form received via mail should probably default to the "reply-to:" of the message. Together, these two ideas let HTML forms be served over HTTP but sent back via mail, or let forms be sent by mail, filled out by HTML-aware mail recipients, and the results mailed back πŸ”

5.7 Remote files with third-party transfer 🌍

Sometimes the user operating the client might want to specify a URL for remote data instead of a local file. So is there a way to let the browser send the server a pointer to the external data instead of the entire contents? One option: the client could send the server data of type message/external-body with access-type set to, say, uri, and the URL of the remote data in the body of the message πŸͺ„

5.8 File transfer with ENCTYPE=x-www-form-urlencoded πŸ™ˆ

If a form has <INPUT TYPE=file> elements but no ENCTYPE in the enclosing <FORM>, the behavior is not specified 🀷 It's probably not a great idea to try URN-encoding big chunks of data for servers that don't expect it.

5.9 CRLF used as line separator πŸ“

Like with all MIME transmissions, CRLF is the separator for lines in a POST of the data in multipart/form-data.

The MIMESGML group is proposing a new type called multipart/related 🧩 It has similar features to multipart/form-data, but the use and application of form-data is different enough that form-data is described separately. It might be possible at some point to encode the results of HTML forms (including files) in a multipart/related body part, and that's not incompatible with this proposal ✨

5.11 Non-ASCII field names 🌏

Heads up: MIME headers are generally required to consist only of 7-bit data in the US-ASCII character set πŸ”€ So field names should be encoded according to the prescriptions of RFC 1522 if they contain characters outside that set. In HTML 2.0 the default character set is ISO-8859-1, but non-ASCII characters in field names should still be encoded πŸ™Œ

6. Examples πŸŽ€

Okay, let's do an example 🧁 Say the server supplies the following HTML:

<FORM ACTION="http://server.dom/cgi/handle"
      ENCTYPE="multipart/form-data"
      METHOD=POST>
What is your name? <INPUT TYPE=TEXT NAME=submitter>
What files are you sending? <INPUT TYPE=FILE NAME=pics>
</FORM>

Then the user types "Joe Blow" in the name field, and selects a text file "file1.txt" for the answer to 'What files are you sending?'

The client might send back the following data:

Content-type: multipart/form-data, boundary=AaB03x

--AaB03x
content-disposition: form-data; name="field1"

Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain

 ... contents of file1.txt ...
--AaB03x--

If the user also picks an image file "file2.gif" for the answer to 'What files are you sending?', the client might send back the following data:

Content-type: multipart/form-data, boundary=AaB03x

--AaB03x
content-disposition: form-data; name="field1"

Joe Blow
--AaB03x
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y

--BbC04y
Content-disposition: attachment; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--BbC04y
Content-disposition: attachment; filename="file2.gif"
Content-type: image/gif
Content-Transfer-Encoding: binary

  ...contents of file2.gif...
--BbC04y--
--AaB03x--

7. Registration of multipart/form-data πŸ’œ

The media-type multipart/form-data follows the rules of all multipart MIME data streams as outlined in RFC 1521. It's intended for returning the data that comes out of filling out a form. In a form (in HTML, although other applications may also use forms), there's a series of fields to be supplied by the user who fills out the form. Each field has a name, and within a given form, the names are unique πŸ“‹

multipart/form-data contains a series of parts. Each part is expected to contain a content-disposition header where the value is "form-data", and a name attribute that specifies the field name within the form, e.g., content-disposition: form-data; name="xxxxx", where xxxxx is the field name corresponding to that field. Field names originally in non-ASCII character sets may be encoded using the method outlined in RFC 1522 🌸

As with all multipart MIME types, each part has an optional Content-Type, which defaults to text/plain. If the contents of a file are returned by filling out a form, then the file input is identified as application/octet-stream or the appropriate media type, if known. If multiple files are returned as the result of a single form entry, they can be returned as multipart/mixed embedded within the multipart/form-data πŸ—‚οΈ

Each part may be encoded, and the "content-transfer-encoding" header supplied, if the value of that part does not conform to the default encoding πŸ”§

File inputs may also identify the file name. The file name may be described using the 'filename' parameter of the "content-disposition" header. This isn't required, but it's strongly recommended in any case where the original filename is known, since it's useful or even necessary in many applications 🫢

8. Security Considerations πŸ”

It is important that a user agent not send any file that the user has not explicitly asked to be sent. So HTML interpreting agents are expected to confirm any default file names that might be suggested with <INPUT TYPE=file VALUE="yyyy">. Never have any hidden fields be able to specify any file. 🚨

This proposal does not contain a mechanism for encryption of the data. That should be handled by whatever other mechanisms are in place for secure transmission of data, whether via secure HTTP, or by the security provided by MOSS (described in RFC 1848) πŸ›‘οΈ

Once the file is uploaded, it is up to the receiver to process and store the file appropriately πŸ’Ύ

9. Conclusion ✨

Okay bestie, the whole design is giving flexibility πŸ’…. The client decides how many files it sends and what types they are, the server still gets to decide whether to accept them πŸ›‘, and servers get a chance to talk to browsers that don't support INPUT TYPE "file" at all 🫢.

The change to the HTML DTD is super simple but sooo powerful πŸ‘‘. It opens the door to a way bigger range of services on the World-Wide Web than we can build right now, since there's no proper file submission facility yet. Honestly, this would be an extremely valuable addition to what the Web can do 🌈.


Authors' Addresses πŸ’Œ

Larry Masinter
Xerox Palo Alto Research Center
3333 Coyote Hill Road
Palo Alto, CA 94304

Phone:  (415) 812-4365
Fax:    (415) 812-4333
EMail:   masinter@parc.xerox.com


Ernesto Nebel
XSoft, Xerox Corporation
10875 Rancho Bernardo Road, Suite 200
San Diego, CA 92127-2116

Phone:  (619) 676-7817
Fax:    (619) 676-7865
EMail:   nebel@xsoft.sd.xerox.com

A. Media type registration for multipart/form-data πŸŽ€

Here's the official registration paperwork for the media type, all written out exactly as it appears πŸ“:

Media Type name:
 multipart

Media subtype name:
 form-data

Required parameters:
 none

Optional parameters:
 none

Encoding considerations:
 No additional considerations other than as for other multipart types.

Published specification:
 RFC 1867

Security Considerations πŸ”’

Short but mighty πŸ’€. The multipart/form-data type doesn't introduce any new security considerations of its own. Whatever risks show up are the ones that could come with any of the enclosed parts.


References πŸ“š

[RFC 1521] MIME (Multipurpose Internet Mail Extensions) Part One:
           Mechanisms for Specifying and Describing the Format of
           Internet Message Bodies.  N. Borenstein & N. Freed.
           September 1993.

[RFC 1522] MIME (Multipurpose Internet Mail Extensions) Part Two:
           Message Header Extensions for Non-ASCII Text. K. Moore.
           September 1993.

[RFC 1806] Communicating Presentation Information in Internet
           Messages: The Content-Disposition Header. R. Troost & S.
           Dorner, June 1995.
πŸ“¦ where this page comes from