@@ -1196,8 +1196,10 @@ defmodule Plug.Conn do
11961196 @ doc """
11971197 Reads the headers of a multipart request.
11981198
1199- It returns `{:ok, headers, conn}` with the headers or
1200- `{:done, conn}` if there are no more parts.
1199+ It returns `{:ok, headers, conn}` with the headers,
1200+ `{:error, :too_large, conn}` if the current multipart header block
1201+ exceeds the configured `:length`, or `{:done, conn}` if there are
1202+ no more parts.
12011203
12021204 Once `read_part_headers/2` is invoked, you may call
12031205 `read_part_body/2` to read the body associated to the headers.
@@ -1206,40 +1208,42 @@ defmodule Plug.Conn do
12061208
12071209 ## Options
12081210
1209- * `:length` - sets the maximum number of bytes to read from the body for
1210- each chunk , defaults to `64_000` bytes
1211+ * `:length` - sets the maximum number of bytes to read while parsing the
1212+ current multipart header block , defaults to `64_000` bytes
12111213 * `:read_length` - sets the amount of bytes to read at one time from the
12121214 underlying socket to fill the chunk, defaults to `64_000` bytes
12131215 * `:read_timeout` - sets the timeout for each socket read, defaults to
12141216 `5_000` milliseconds
12151217
12161218 """
1217- @ spec read_part_headers ( t , Keyword . t ( ) ) :: { :ok , headers , t } | { :done , t }
1219+ @ spec read_part_headers ( t , Keyword . t ( ) ) ::
1220+ { :ok , headers , t } | { :error , :too_large , t } | { :done , t }
12181221 def read_part_headers ( % Conn { adapter: { adapter , state } } = conn , opts \\ [ ] ) do
1219- opts = opts ++ [ length: 64_000 , read_length: 64_000 , read_timeout: 5000 ]
1220-
12211222 case init_multipart ( conn ) do
12221223 { boundary , buffer } ->
1224+ opts = opts ++ [ length: 64_000 , read_length: 64_000 , read_timeout: 5000 ]
1225+ length = Keyword . fetch! ( opts , :length )
12231226 { data , state } = read_multipart_from_buffer_or_adapter ( buffer , adapter , state , opts )
1224- read_part_headers ( conn , data , boundary , adapter , state , opts )
1227+ read_part_headers ( conn , data , length , boundary , adapter , state , opts )
12251228
12261229 :done ->
12271230 { :done , conn }
12281231 end
12291232 end
12301233
1231- defp read_part_headers ( conn , data , boundary , adapter , state , opts ) do
1234+ defp read_part_headers ( conn , data , length , boundary , adapter , state , opts ) do
12321235 case :plug_multipart . parse_headers ( data , boundary ) do
1236+ { :ok , _headers , rest } when byte_size ( data ) - byte_size ( rest ) > length ->
1237+ { :error , :too_large , store_multipart ( conn , { boundary , data } , adapter , state ) }
1238+
12331239 { :ok , headers , rest } ->
12341240 { :ok , headers , store_multipart ( conn , { boundary , rest } , adapter , state ) }
12351241
12361242 :more ->
1237- { _ , next , state } = next_multipart ( adapter , state , opts )
1238- read_part_headers ( conn , data <> next , boundary , adapter , state , opts )
1243+ read_part_headers_more ( conn , data , length , boundary , adapter , state , opts )
12391244
12401245 { :more , rest } ->
1241- { _ , next , state } = next_multipart ( adapter , state , opts )
1242- read_part_headers ( conn , rest <> next , boundary , adapter , state , opts )
1246+ read_part_headers_more ( conn , rest , length , boundary , adapter , state , opts )
12431247
12441248 { :done , _ } ->
12451249 { :done , store_multipart ( conn , :done , adapter , state ) }
@@ -1328,6 +1332,16 @@ defmodule Plug.Conn do
13281332 % { put_in ( conn . private [ :plug_multipart ] , multipart ) | adapter: { adapter , state } }
13291333 end
13301334
1335+ defp read_part_headers_more ( conn , data , length , boundary , adapter , state , _opts )
1336+ when byte_size ( data ) >= length do
1337+ { :error , :too_large , store_multipart ( conn , { boundary , data } , adapter , state ) }
1338+ end
1339+
1340+ defp read_part_headers_more ( conn , data , length , boundary , adapter , state , opts ) do
1341+ { _ , next , state } = next_multipart ( adapter , state , opts )
1342+ read_part_headers ( conn , data <> next , length , boundary , adapter , state , opts )
1343+ end
1344+
13311345 defp read_multipart_from_buffer_or_adapter ( "" , adapter , state , opts ) do
13321346 { _ , data , state } = adapter . read_req_body ( state , opts )
13331347 { data , state }
0 commit comments