multipart.asciidoc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. [[multipart]]
  2. == Multipart requests
  3. Multipart originates from MIME, an Internet standard that
  4. extends the format of emails.
  5. A multipart message is a list of parts. A part contains
  6. headers and a body. The body of the parts may be
  7. of any media type, and contain text or binary data.
  8. It is possible for parts to contain a multipart media
  9. type.
  10. In the context of HTTP, multipart is most often used
  11. with the `multipart/form-data` media type. It is what
  12. browsers use to upload files through HTML forms.
  13. The `multipart/byteranges` is also common. It is the
  14. media type used to send arbitrary bytes from a resource,
  15. enabling clients to resume downloads.
  16. === Form-data
  17. In the normal case, when a form is submitted, the
  18. browser will use the `application/x-www-form-urlencoded`
  19. content-type. This type is just a list of keys and
  20. values and is therefore not fit for uploading files.
  21. That's where the `multipart/form-data` content-type
  22. comes in. When the form is configured to use this
  23. content-type, the browser will create a multipart
  24. message where each part corresponds to a field on
  25. the form. For files, it also adds some metadata in
  26. the part headers, like the file name.
  27. A form with a text input, a file input and a select
  28. choice box will result in a multipart message with
  29. three parts, one for each field.
  30. The browser does its best to determine the media type
  31. of the files it sends this way, but you should not
  32. rely on it for determining the contents of the file.
  33. Proper investigation of the contents is recommended.
  34. === Checking for multipart messages
  35. The content-type header indicates the presence of
  36. a multipart message:
  37. [source,erlang]
  38. ----
  39. {<<"multipart">>, <<"form-data">>, _}
  40. = cowboy_req:parse_header(<<"content-type">>, Req).
  41. ----
  42. === Reading a multipart message
  43. Cowboy provides two sets of functions for reading
  44. request bodies as multipart messages.
  45. The `cowboy_req:read_part/1,2` functions return the
  46. next part's headers, if any.
  47. The `cowboy_req:read_part_body/1,2` functions return
  48. the current part's body. For large bodies you may
  49. need to call the function multiple times.
  50. To read a multipart message you need to iterate over
  51. all its parts:
  52. [source,erlang]
  53. ----
  54. multipart(Req0) ->
  55. case cowboy_req:read_part(Req0) of
  56. {ok, _Headers, Req1} ->
  57. {ok, _Body, Req} = cowboy_req:read_part_body(Req1),
  58. multipart(Req);
  59. {done, Req} ->
  60. Req
  61. end.
  62. ----
  63. When part bodies are too large, Cowboy will return
  64. a `more` tuple, and allow you to loop until the part
  65. body has been fully read.
  66. The function `cow_multipart:form_data/1` can be used
  67. to quickly obtain information about a part from a
  68. `multipart/form-data` message. The function returns
  69. a `data` or a `file` tuple depending on whether this
  70. is a normal field or a file being uploaded.
  71. The following snippet will use this function and
  72. use different strategies depending on whether the
  73. part is a file:
  74. [source,erlang]
  75. ----
  76. multipart(Req0) ->
  77. case cowboy_req:read_part(Req0) of
  78. {ok, Headers, Req1} ->
  79. Req = case cow_multipart:form_data(Headers) of
  80. {data, _FieldName} ->
  81. {ok, _Body, Req2} = cowboy_req:read_part_body(Req1),
  82. Req2;
  83. {file, _FieldName, _Filename, _CType, _CTransferEncoding} ->
  84. stream_file(Req1)
  85. end,
  86. multipart(Req);
  87. {done, Req} ->
  88. Req
  89. end.
  90. stream_file(Req0) ->
  91. case cowboy_req:read_part_body(Req0) of
  92. {ok, _Body, Req} ->
  93. Req;
  94. {more, _Body, Req} ->
  95. stream_file(Req)
  96. end.
  97. ----
  98. Both the part header and body reading functions can take
  99. options that will be given to the request body reading
  100. functions. By default, `cowboy_req:read_part/1` reads
  101. up to 64KB for up to 5 seconds. `cowboy_req:read_part_body/1`
  102. has the same defaults as `cowboy_req:read_body/1`.
  103. To change the defaults for part headers:
  104. [source,erlang]
  105. cowboy_req:read_part(Req, #{length => 128000}).
  106. And for part bodies:
  107. [source,erlang]
  108. cowboy_req:read_part_body(Req, #{length => 1000000, period => 7000}).
  109. === Skipping unwanted parts
  110. Part bodies do not have to be read. Cowboy will automatically
  111. skip it when you request the next part's body.
  112. The following snippet reads all part headers and skips
  113. all bodies:
  114. [source,erlang]
  115. ----
  116. multipart(Req0) ->
  117. case cowboy_req:read_part(Req0) of
  118. {ok, _Headers, Req} ->
  119. multipart(Req);
  120. {done, Req} ->
  121. Req
  122. end.
  123. ----
  124. Similarly, if you start reading the body and it ends up
  125. being too big, you can simply continue with the next part.
  126. Cowboy will automatically skip what remains.
  127. While Cowboy can skip part bodies automatically, the read
  128. rate is not configurable. Depending on your application
  129. you may want to skip manually, in particular if you observe
  130. poor performance while skipping.
  131. You do not have to read all parts either. You can stop
  132. reading as soon as you find the data you need.
  133. // @todo Cover the building of multipart messages.