@@ -1167,8 +1167,10 @@ defmodule Plug.Conn do
11671167 @ doc """
11681168 Reads the headers of a multipart request.
11691169
1170- It returns `{:ok, headers, conn}` with the headers or
1171- `{:done, conn}` if there are no more parts.
1170+ It returns `{:ok, headers, conn}` with the headers,
1171+ `{:error, :too_large, conn}` if the current multipart header block
1172+ exceeds the configured `:length`, or `{:done, conn}` if there are
1173+ no more parts.
11721174
11731175 Once `read_part_headers/2` is invoked, you may call
11741176 `read_part_body/2` to read the body associated to the headers.
@@ -1177,40 +1179,42 @@ defmodule Plug.Conn do
11771179
11781180 ## Options
11791181
1180- * `:length` - sets the maximum number of bytes to read from the body for
1181- each chunk , defaults to `64_000` bytes
1182+ * `:length` - sets the maximum number of bytes to read while parsing the
1183+ current multipart header block , defaults to `64_000` bytes
11821184 * `:read_length` - sets the amount of bytes to read at one time from the
11831185 underlying socket to fill the chunk, defaults to `64_000` bytes
11841186 * `:read_timeout` - sets the timeout for each socket read, defaults to
11851187 `5_000` milliseconds
11861188
11871189 """
1188- @ spec read_part_headers ( t , Keyword . t ( ) ) :: { :ok , headers , t } | { :done , t }
1190+ @ spec read_part_headers ( t , Keyword . t ( ) ) ::
1191+ { :ok , headers , t } | { :error , :too_large , t } | { :done , t }
11891192 def read_part_headers ( % Conn { adapter: { adapter , state } } = conn , opts \\ [ ] ) do
1190- opts = opts ++ [ length: 64_000 , read_length: 64_000 , read_timeout: 5000 ]
1191-
11921193 case init_multipart ( conn ) do
11931194 { boundary , buffer } ->
1195+ opts = opts ++ [ length: 64_000 , read_length: 64_000 , read_timeout: 5000 ]
1196+ length = Keyword . fetch! ( opts , :length )
11941197 { data , state } = read_multipart_from_buffer_or_adapter ( buffer , adapter , state , opts )
1195- read_part_headers ( conn , data , boundary , adapter , state , opts )
1198+ read_part_headers ( conn , data , length , boundary , adapter , state , opts )
11961199
11971200 :done ->
11981201 { :done , conn }
11991202 end
12001203 end
12011204
1202- defp read_part_headers ( conn , data , boundary , adapter , state , opts ) do
1205+ defp read_part_headers ( conn , data , length , boundary , adapter , state , opts ) do
12031206 case :plug_multipart . parse_headers ( data , boundary ) do
1207+ { :ok , _headers , rest } when byte_size ( data ) - byte_size ( rest ) > length ->
1208+ { :error , :too_large , store_multipart ( conn , { boundary , data } , adapter , state ) }
1209+
12041210 { :ok , headers , rest } ->
12051211 { :ok , headers , store_multipart ( conn , { boundary , rest } , adapter , state ) }
12061212
12071213 :more ->
1208- { _ , next , state } = next_multipart ( adapter , state , opts )
1209- read_part_headers ( conn , data <> next , boundary , adapter , state , opts )
1214+ read_part_headers_more ( conn , data , length , boundary , adapter , state , opts )
12101215
12111216 { :more , rest } ->
1212- { _ , next , state } = next_multipart ( adapter , state , opts )
1213- read_part_headers ( conn , rest <> next , boundary , adapter , state , opts )
1217+ read_part_headers_more ( conn , rest , length , boundary , adapter , state , opts )
12141218
12151219 { :done , _ } ->
12161220 { :done , store_multipart ( conn , :done , adapter , state ) }
@@ -1299,6 +1303,16 @@ defmodule Plug.Conn do
12991303 % { put_in ( conn . private [ :plug_multipart ] , multipart ) | adapter: { adapter , state } }
13001304 end
13011305
1306+ defp read_part_headers_more ( conn , data , length , boundary , adapter , state , _opts )
1307+ when byte_size ( data ) >= length do
1308+ { :error , :too_large , store_multipart ( conn , { boundary , data } , adapter , state ) }
1309+ end
1310+
1311+ defp read_part_headers_more ( conn , data , length , boundary , adapter , state , opts ) do
1312+ { _ , next , state } = next_multipart ( adapter , state , opts )
1313+ read_part_headers ( conn , data <> next , length , boundary , adapter , state , opts )
1314+ end
1315+
13021316 defp read_multipart_from_buffer_or_adapter ( "" , adapter , state , opts ) do
13031317 { _ , data , state } = adapter . read_req_body ( state , opts )
13041318 { data , state }
0 commit comments