Skip to content

Commit d377e0a

Browse files
committed
inets: Remove max_client_body_chunk support
This option has not worked since it was added and fixing it is not trivial, so we remove it completely and then if the need arises we'll fix it later.
1 parent 374ca47 commit d377e0a

4 files changed

Lines changed: 18 additions & 93 deletions

File tree

lib/inets/doc/guides/hardening.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,6 @@ requests that can exhaust memory. Set explicit limits:
250250
exceeds this value with a 413 response, before reading the body. Default:
251251
`100_000_000` (100 MB).
252252

253-
- **[`max_client_body_chunk`](`m:httpd#max_client_body_chunk`)** - When handling large PUT or POST bodies via
254-
`mod_esi`, setting this option enforces chunked delivery to the ESI
255-
callback. This prevents the server from buffering the entire request body
256-
in memory, which could be exploited to cause memory exhaustion.
257-
258253
> #### Note {: .info }
259254
>
260255
> `max_body_size` and `max_content_length` serve different purposes.

lib/inets/src/http_server/httpd.erl

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,6 @@ property list.
195195
the server closes the connection. The server closes it even if there are
196196
queued request. Default is no limit.
197197

198-
- [](){: #max_client_body_chunk } **`{max_client_body_chunk, integer()}`**
199-
Enforces chunking of a HTTP PUT or POST body data to be delivered to the
200-
mod_esi callback. Note this is not supported for mod_cgi. Default is no limit
201-
e.i the whole body is delivered as one entity, which could be very memory
202-
consuming. `m:mod_esi`.
203-
204198
[](){: #props_admin }
205199

206200
### Administrative Properties
@@ -1021,8 +1015,7 @@ reload_config(ConfigFile, Mode) ->
10211015
| {max_header_size, integer()}
10221016
| {max_content_length, integer()}
10231017
| {max_uri_size, integer()}
1024-
| {max_keep_alive_request, integer()}
1025-
| {max_client_body_chunk, integer()},
1018+
| {max_keep_alive_request, integer()},
10261019
AdminOption :: {mime_types, [{MimeType :: string(), Extension :: string()}] | Path}
10271020
| {mime_type, string()}
10281021
| {server_admin, string()}
@@ -1073,8 +1066,7 @@ server.
10731066
| {max_header_size, integer()}
10741067
| {max_content_length, integer()}
10751068
| {max_uri_size, integer()}
1076-
| {max_keep_alive_request, integer()}
1077-
| {max_client_body_chunk, integer()},
1069+
| {max_keep_alive_request, integer()},
10781070
AdminOption :: {mime_types, [{MimeType :: string(), Extension :: string()}] | Path}
10791071
| {mime_type, string()}
10801072
| {server_admin, string()}
@@ -1111,8 +1103,7 @@ server.
11111103
| {max_header_size, integer()}
11121104
| {max_content_length, integer()}
11131105
| {max_uri_size, integer()}
1114-
| {max_keep_alive_request, integer()}
1115-
| {max_client_body_chunk, integer()},
1106+
| {max_keep_alive_request, integer()},
11161107
AdminOption :: {mime_types, [{MimeType :: string(), Extension :: string()}] | Path}
11171108
| {mime_type, string()}
11181109
| {server_admin, string()}
@@ -1166,8 +1157,7 @@ info(Address, Port) when is_integer(Port) ->
11661157
| {max_header_size, integer()}
11671158
| {max_content_length, integer()}
11681159
| {max_uri_size, integer()}
1169-
| {max_keep_alive_request, integer()}
1170-
| {max_client_body_chunk, integer()},
1160+
| {max_keep_alive_request, integer()},
11711161
AdminOption :: {mime_types, [{MimeType :: string(), Extension :: string()}] | Path}
11721162
| {mime_type, string()}
11731163
| {server_admin, string()}
@@ -1205,8 +1195,7 @@ info(Address, Port) when is_integer(Port) ->
12051195
| {max_header_size, integer()}
12061196
| {max_content_length, integer()}
12071197
| {max_uri_size, integer()}
1208-
| {max_keep_alive_request, integer()}
1209-
| {max_client_body_chunk, integer()},
1198+
| {max_keep_alive_request, integer()},
12101199
AdminOption :: {mime_types, [{MimeType :: string(), Extension :: string()}] | Path}
12111200
| {mime_type, string()}
12121201
| {server_admin, string()}
@@ -1263,8 +1252,7 @@ options of the server.
12631252
| {max_header_size, integer()}
12641253
| {max_content_length, integer()}
12651254
| {max_uri_size, integer()}
1266-
| {max_keep_alive_request, integer()}
1267-
| {max_client_body_chunk, integer()},
1255+
| {max_keep_alive_request, integer()},
12681256
AdminOption :: {mime_types, [{MimeType :: string(), Extension :: string()}] | Path}
12691257
| {mime_type, string()}
12701258
| {server_admin, string()}

lib/inets/src/http_server/httpd_request_handler.erl

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,8 @@ handle_cast(Msg, #state{mod = #mod{config_db = Db} = ModData} = State) ->
236236
%%--------------------------------------------------------------------
237237
handle_info({Proto, Socket, Data},
238238
#state{mfa = {Module, Function, Args},
239-
chunk = {ChunkState, _},
240239
mod = #mod{socket_type = SockType,
241-
socket = Socket} = ModData} = State)
240+
socket = Socket} = ModData} = State)
242241
when (((Proto =:= tcp) orelse
243242
(Proto =:= ssl) orelse
244243
(Proto =:= dummy)) andalso is_binary(Data)) ->
@@ -266,7 +265,7 @@ handle_info({Proto, Socket, Data},
266265
{stop, normal, State#state{response_sent = true,
267266
mod = NewModData}};
268267
{error, {version_error, ErrCode, ErrStr}, Version} ->
269-
NewModData = ModData#mod{http_version = Version},
268+
NewModData = ModData#mod{http_version = Version},
270269
httpd_response:send_status(NewModData, ErrCode, ErrStr),
271270
{stop, normal, State#state{response_sent = true,
272271
mod = NewModData}};
@@ -275,18 +274,15 @@ handle_info({Proto, Socket, Data},
275274
httpd_response:send_status(NewModData, ErrCode, ErrStr),
276275
{stop, normal, State#state{response_sent = true,
277276
mod = NewModData}};
277+
NewMFA ->
278+
setopts(Socket, SockType, [{active, once}]),
279+
case NewDataSize of
280+
undefined ->
281+
{noreply, State#state{mfa = NewMFA}};
282+
_ ->
283+
{noreply, State#state{mfa = NewMFA, data = NewDataSize}}
284+
end
278285

279-
{http_chunk = Module, Function, Args} when ChunkState =/= undefined ->
280-
NewState = handle_chunk(Module, Function, Args, State),
281-
{noreply, NewState};
282-
NewMFA ->
283-
setopts(Socket, SockType, [{active, once}]),
284-
case NewDataSize of
285-
undefined ->
286-
{noreply, State#state{mfa = NewMFA}};
287-
_ ->
288-
{noreply, State#state{mfa = NewMFA, data = NewDataSize}}
289-
end
290286
end;
291287

292288
%% Error cases
@@ -535,7 +531,6 @@ handle_body(#state{headers = Headers, body = Body,
535531
{stop, normal, State#state{response_sent = true}};
536532
_ ->
537533
Length = list_to_integer(Headers#http_request_h.'content-length'),
538-
MaxChunk = max_client_body_chunk(ConfigDB),
539534
case Length =< MaxBodySize orelse MaxBodySize == nolimit of
540535
true ->
541536
case httpd_request:body_chunk_first(Body, Length, MaxChunk) of
@@ -617,29 +612,6 @@ expect(Headers, _, ConfigDB) ->
617612
end
618613
end.
619614

620-
handle_chunk(http_chunk = Module, decode_data = Function,
621-
[ChunkSize, TotalChunk, {MaxBodySize, BodySoFar, _AccLength, MaxHeaderSize}],
622-
#state{chunk = {_, CbState},
623-
mod = #mod{socket_type = SockType,
624-
socket = Socket} = ModData} = State) ->
625-
{continue, NewCbState} = httpd_response:handle_continuation(ModData#mod{entity_body =
626-
{continue, BodySoFar, CbState}}),
627-
setopts(Socket, SockType, [{active, once}]),
628-
State#state{chunk = {continue, NewCbState}, mfa = {Module, Function, [ChunkSize, TotalChunk, {MaxBodySize, <<>>, 0, MaxHeaderSize}]}};
629-
630-
handle_chunk(http_chunk = Module, decode_size = Function,
631-
[Data, HexList, _AccSize, {MaxBodySize, BodySoFar, _AccLength, MaxHeaderSize}],
632-
#state{chunk = {_, CbState},
633-
mod = #mod{socket_type = SockType,
634-
socket = Socket} = ModData} = State) ->
635-
{continue, NewCbState} = httpd_response:handle_continuation(ModData#mod{entity_body = {continue, BodySoFar, CbState}}),
636-
setopts(Socket, SockType, [{active, once}]),
637-
State#state{chunk = {continue, NewCbState}, mfa = {Module, Function, [Data, HexList, 0, {MaxBodySize, <<>>, 0, MaxHeaderSize}]}};
638-
handle_chunk(Module, Function, Args, #state{mod = #mod{socket_type = SockType,
639-
socket = Socket}} = State) ->
640-
setopts(Socket, SockType, [{active, once}]),
641-
State#state{mfa = {Module, Function, Args}}.
642-
643615
handle_internal_chunk(#state{chunk = {ChunkState, CbState}, body = Chunk,
644616
mod = #mod{socket_type = SockType,
645617
socket = Socket} = ModData} = State, Module, Function, Args)->

lib/inets/src/http_server/mod_esi.erl

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -138,27 +138,6 @@ that no HTTP header fields will be generated. This behaviour depends on the
138138

139139
- `Input`: query data of a GET request or the body of a PUT or POST request.
140140

141-
The default behavior (legacy reasons) for delivering the body, is that the
142-
whole body is gathered and converted to a string. But if the httpd config
143-
parameter [`max_client_body_chunk`](`m:httpd#max_client_body_chunk`) is set,
144-
the body will be delivered as binary chunks instead. The maximum size of the
145-
chunks is either [`max_client_body_chunk`](`m:httpd#max_client_body_chunk`) or
146-
decided by the client if it uses HTTP chunked encoding to send the body.
147-
148-
When using the chunking mechanism, this callback must return `{continue,
149-
State::term()}` for all calls where `Input` is `{first, Data::binary()}` or
150-
`{continue, Data::binary(), State::term()}`. When `Input` is `{last,
151-
Data::binary(), State::term()}` the return value will be ignored.
152-
153-
The input `State` is the last returned `State`, in it the callback can include
154-
any data that it needs to keep track of when handling the chunks.
155-
156-
> #### Note {: .info }
157-
>
158-
> Note that if the body is small all data may be delivered in only one chunk and
159-
> then the callback will be called with `{last, Data::binary(), undefined}`
160-
> without getting called with `{first, Data::binary()}`.
161-
162141
## Setting a response status
163142

164143
To set the response status code, the special `status` response header can be
@@ -170,20 +149,11 @@ JSON response body, one could pass the following:
170149
```
171150
""".
172151
-doc(#{group => <<"ESI Callback Functions">>}).
173-
-callback 'Function'(SessionID, Env, Input) -> {continue, State} | _
152+
-callback 'Function'(SessionID, Env, Input) -> _
174153
when
175154
SessionID :: session_id(),
176155
Env :: [env()],
177-
Input :: string() | ChunkedData,
178-
ChunkedData ::
179-
{first, Data :: binary()} |
180-
{continue,
181-
Data :: binary(),
182-
State :: term()} |
183-
{last,
184-
Data :: binary(),
185-
State :: term()},
186-
State :: term().
156+
Input :: string().
187157

188158
-optional_callbacks(['Function'/3]).
189159

0 commit comments

Comments
 (0)