diff options
author | Loïc Hoguin <[email protected]> | 2018-11-19 13:29:35 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2018-11-19 13:29:35 +0100 |
commit | 3edee0ace8f3f12653381e8038461689363c9541 (patch) | |
tree | 25c351b121ff008ed7a73ee945dc1f2d28a025c1 /docs/en/cowboy/2.6/guide/multipart.asciidoc | |
parent | 4ddd4e856a43c800227878c4b145aca15ce3f579 (diff) | |
download | ninenines.eu-3edee0ace8f3f12653381e8038461689363c9541.tar.gz ninenines.eu-3edee0ace8f3f12653381e8038461689363c9541.tar.bz2 ninenines.eu-3edee0ace8f3f12653381e8038461689363c9541.zip |
Cowboy 2.6.0
Diffstat (limited to 'docs/en/cowboy/2.6/guide/multipart.asciidoc')
-rw-r--r-- | docs/en/cowboy/2.6/guide/multipart.asciidoc | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/docs/en/cowboy/2.6/guide/multipart.asciidoc b/docs/en/cowboy/2.6/guide/multipart.asciidoc new file mode 100644 index 00000000..0825244c --- /dev/null +++ b/docs/en/cowboy/2.6/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. |