multipart.asciidoc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. [[multipart]]
  2. == Multipart requests
  3. Multipart originates from MIME, an Internet standard that
  4. extends the format of emails. Multipart messages are a
  5. container for parts of any content-type.
  6. For example, a multipart message may have a part
  7. containing text and a second part containing an
  8. image. This is what allows you to attach files
  9. to emails.
  10. In the context of HTTP, multipart is most often used
  11. with the `multipart/form-data` content-type. This is
  12. the content-type you have to use when you want browsers
  13. to be allowed to upload files through HTML forms.
  14. Multipart is of course not required for uploading
  15. files, it is only required when you want to do so
  16. through HTML forms.
  17. You can read and parse multipart messages using the
  18. Req object directly.
  19. Cowboy defines two functions that allows you to get
  20. information about each part and read their contents.
  21. === Structure
  22. A multipart message is a list of parts. Parts may
  23. contain either a multipart message or a non-multipart
  24. content-type. This allows parts to be arranged in a
  25. tree structure, although this is a rare case as far
  26. as the Web is concerned.
  27. === Form-data
  28. In the normal case, when a form is submitted, the
  29. browser will use the `application/x-www-form-urlencoded`
  30. content-type. This type is just a list of keys and
  31. values and is therefore not fit for uploading files.
  32. That's where the `multipart/form-data` content-type
  33. comes in. When the form is configured to use this
  34. content-type, the browser will use one part of the
  35. message for each form field. This means that a file
  36. input field will be sent in its own part, but the
  37. same applies to all other kinds of fields.
  38. A form with a text input, a file input and a select
  39. choice box will result in a multipart message with
  40. three parts, one for each field.
  41. The browser does its best to determine the content-type
  42. of the files it sends this way, but you should not
  43. rely on it for determining the contents of the file.
  44. Proper investigation of the contents is recommended.
  45. === Checking the content-type
  46. While there is a variety of multipart messages, the
  47. most common on the Web is `multipart/form-data`. It's
  48. the type of message being sent when an HTML form
  49. allows uploading files.
  50. You can quickly figure out if a multipart message
  51. has been sent by parsing the `content-type` header.
  52. [source,erlang]
  53. ----
  54. {<<"multipart">>, <<"form-data">>, _}
  55. = cowboy_req:parse_header(<<"content-type">>, Req).
  56. ----
  57. === Reading a multipart message
  58. To read a message you have to iterate over all its
  59. parts. Then, for each part, you can inspect its headers
  60. and read its body.
  61. [source,erlang]
  62. ----
  63. multipart(Req) ->
  64. case cowboy_req:part(Req) of
  65. {ok, _Headers, Req2} ->
  66. {ok, _Body, Req3} = cowboy_req:part_body(Req2),
  67. multipart(Req3);
  68. {done, Req2} ->
  69. Req2
  70. end.
  71. ----
  72. Parts do not have a size limit. When a part body is
  73. too big, Cowboy will return what it read so far and
  74. allow you to continue if you wish to do so.
  75. The function `cow_multipart:form_data/1` can be used
  76. to quickly obtain information about a part from a
  77. `multipart/form-data` message. This function will
  78. tell you if the part is for a normal field or if it
  79. is a file being uploaded.
  80. This can be used for example to allow large part bodies
  81. for files but crash when a normal field is too large.
  82. [source,erlang]
  83. ----
  84. multipart(Req) ->
  85. case cowboy_req:part(Req) of
  86. {ok, Headers, Req2} ->
  87. Req4 = case cow_multipart:form_data(Headers) of
  88. {data, _FieldName} ->
  89. {ok, _Body, Req3} = cowboy_req:part_body(Req2),
  90. Req3;
  91. {file, _FieldName, _Filename, _CType, _CTransferEncoding} ->
  92. stream_file(Req2)
  93. end,
  94. multipart(Req4);
  95. {done, Req2} ->
  96. Req2
  97. end.
  98. stream_file(Req) ->
  99. case cowboy_req:part_body(Req) of
  100. {ok, _Body, Req2} ->
  101. Req2;
  102. {more, _Body, Req2} ->
  103. stream_file(Req2)
  104. end.
  105. ----
  106. By default the body chunk Cowboy will return is limited
  107. to 8MB. This can of course be overriden. Both functions
  108. can take a second argument, the same list of options that
  109. will be passed to `cowboy_req:body/2` function.
  110. === Skipping unwanted parts
  111. If you do not want to read a part's body, you can skip it.
  112. Skipping is easy. If you do not call the function to read
  113. the part's body, Cowboy will automatically skip it when
  114. you request the next part.
  115. The following snippet reads all part headers and skips
  116. all bodies:
  117. [source,erlang]
  118. ----
  119. multipart(Req) ->
  120. case cowboy_req:part(Req) of
  121. {ok, _Headers, Req2} ->
  122. multipart(Req2);
  123. {done, Req2} ->
  124. Req2
  125. end.
  126. ----
  127. Similarly, if you start reading the body and it ends up
  128. being too big, you can simply continue with the next part,
  129. Cowboy will automatically skip what remains.
  130. Note that the skipping rate may not be adequate for your
  131. application. If you observe poor performance when skipping,
  132. you might want to consider manually skipping by calling
  133. the `cowboy_req:part_body/1` function directly.
  134. And if you started reading the message but decide that you
  135. do not need the remaining parts, you can simply stop reading
  136. entirely and Cowboy will automatically figure out what to do.