summaryrefslogtreecommitdiffstats
path: root/docs/en/cowboy/2.12/guide/multipart.asciidoc
diff options
context:
space:
mode:
Diffstat (limited to 'docs/en/cowboy/2.12/guide/multipart.asciidoc')
-rw-r--r--docs/en/cowboy/2.12/guide/multipart.asciidoc169
1 files changed, 169 insertions, 0 deletions
diff --git a/docs/en/cowboy/2.12/guide/multipart.asciidoc b/docs/en/cowboy/2.12/guide/multipart.asciidoc
new file mode 100644
index 00000000..0825244c
--- /dev/null
+++ b/docs/en/cowboy/2.12/guide/multipart.asciidoc
@@ -0,0 +1,169 @@
+[[multipart]]
+== Multipart requests
+
+Multipart originates from MIME, an Internet standard that
+extends the format of emails.
+
+A multipart message is a list of parts. A part contains
+headers and a body. The body of the parts may be
+of any media type, and contain text or binary data.
+It is possible for parts to contain a multipart media
+type.
+
+In the context of HTTP, multipart is most often used
+with the `multipart/form-data` media type. It is what
+browsers use to upload files through HTML forms.
+
+The `multipart/byteranges` is also common. It is the
+media type used to send arbitrary bytes from a resource,
+enabling clients to resume downloads.
+
+=== Form-data
+
+In the normal case, when a form is submitted, the
+browser will use the `application/x-www-form-urlencoded`
+content-type. This type is just a list of keys and
+values and is therefore not fit for uploading files.
+
+That's where the `multipart/form-data` content-type
+comes in. When the form is configured to use this
+content-type, the browser will create a multipart
+message where each part corresponds to a field on
+the form. For files, it also adds some metadata in
+the part headers, like the file name.
+
+A form with a text input, a file input and a select
+choice box will result in a multipart message with
+three parts, one for each field.
+
+The browser does its best to determine the media type
+of the files it sends this way, but you should not
+rely on it for determining the contents of the file.
+Proper investigation of the contents is recommended.
+
+=== Checking for multipart messages
+
+The content-type header indicates the presence of
+a multipart message:
+
+[source,erlang]
+----
+{<<"multipart">>, <<"form-data">>, _}
+ = cowboy_req:parse_header(<<"content-type">>, Req).
+----
+
+=== Reading a multipart message
+
+Cowboy provides two sets of functions for reading
+request bodies as multipart messages.
+
+The `cowboy_req:read_part/1,2` functions return the
+next part's headers, if any.
+
+The `cowboy_req:read_part_body/1,2` functions return
+the current part's body. For large bodies you may
+need to call the function multiple times.
+
+To read a multipart message you need to iterate over
+all its parts:
+
+[source,erlang]
+----
+multipart(Req0) ->
+ case cowboy_req:read_part(Req0) of
+ {ok, _Headers, Req1} ->
+ {ok, _Body, Req} = cowboy_req:read_part_body(Req1),
+ multipart(Req);
+ {done, Req} ->
+ Req
+ end.
+----
+
+When part bodies are too large, Cowboy will return
+a `more` tuple, and allow you to loop until the part
+body has been fully read.
+
+The function `cow_multipart:form_data/1` can be used
+to quickly obtain information about a part from a
+`multipart/form-data` message. The function returns
+a `data` or a `file` tuple depending on whether this
+is a normal field or a file being uploaded.
+
+The following snippet will use this function and
+use different strategies depending on whether the
+part is a file:
+
+[source,erlang]
+----
+multipart(Req0) ->
+ case cowboy_req:read_part(Req0) of
+ {ok, Headers, Req1} ->
+ Req = case cow_multipart:form_data(Headers) of
+ {data, _FieldName} ->
+ {ok, _Body, Req2} = cowboy_req:read_part_body(Req1),
+ Req2;
+ {file, _FieldName, _Filename, _CType} ->
+ stream_file(Req1)
+ end,
+ multipart(Req);
+ {done, Req} ->
+ Req
+ end.
+
+stream_file(Req0) ->
+ case cowboy_req:read_part_body(Req0) of
+ {ok, _LastBodyChunk, Req} ->
+ Req;
+ {more, _BodyChunk, Req} ->
+ stream_file(Req)
+ end.
+----
+
+Both the part header and body reading functions can take
+options that will be given to the request body reading
+functions. By default, `cowboy_req:read_part/1` reads
+up to 64KB for up to 5 seconds. `cowboy_req:read_part_body/1`
+has the same defaults as `cowboy_req:read_body/1`.
+
+To change the defaults for part headers:
+
+[source,erlang]
+cowboy_req:read_part(Req, #{length => 128000}).
+
+And for part bodies:
+
+[source,erlang]
+cowboy_req:read_part_body(Req, #{length => 1000000, period => 7000}).
+
+=== Skipping unwanted parts
+
+Part bodies do not have to be read. Cowboy will automatically
+skip it when you request the next part's body.
+
+The following snippet reads all part headers and skips
+all bodies:
+
+[source,erlang]
+----
+multipart(Req0) ->
+ case cowboy_req:read_part(Req0) of
+ {ok, _Headers, Req} ->
+ multipart(Req);
+ {done, Req} ->
+ Req
+ end.
+----
+
+Similarly, if you start reading the body and it ends up
+being too big, you can simply continue with the next part.
+Cowboy will automatically skip what remains.
+
+While Cowboy can skip part bodies automatically, the read
+rate is not configurable. Depending on your application
+you may want to skip manually, in particular if you observe
+poor performance while skipping.
+
+You do not have to read all parts either. You can stop
+reading as soon as you find the data you need.
+
+// @todo Cover the building of multipart messages.