Commit f71ee69f authored by Siebers, Michael's avatar Siebers, Michael
Browse files

Merge branch '61-setting-content-length-header-too-high-results-in-server-error' into 'master'

Resolve "Setting Content-Length header too high results in Server Error"

Closes #61

See merge request cogsys/dare2del/demonstrator!31
parents a75df315 9cfed5d3
......@@ -445,13 +445,11 @@ system_test:robust against wrong body:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_wrong_content_payload
allow_failure: true # see issue #61
system_test:robust against superfluous payload:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_wrong_content_empty
allow_failure: true # see issue #61
system_test:bg robust against non-item payload:
extends: .system_test:run_with_data
......@@ -462,7 +460,6 @@ system_test:irrelevant robust against non-path payload:
extends: .system_test:run_with_data
variables:
TEST_NAME: robust_irrelevant@file_non_path_payload
allow_failure: true # see issue #64
system_test:explain robust against non-path payload:
extends: .system_test:run_with_data
......
......@@ -82,8 +82,27 @@ http:map_exception_to_http_status_hook(length_required,
message:"Header 'Content-Length' missing."})),
string_codes(Message, MessageBytes).
/* request_timeout => 408 Request Timeout
*
* Client send a POST request which requires a body. However, reading the body
* timed out. Most probable cause is an erroneous Content-Length header,
* promising more bytes than will actually be transmitted. Depending on the size
* of the body also a client's slow connection speed could be the cause.
*/
http:map_exception_to_http_status_hook(request_timeout,
bytes('application/json', MessageBytes),
[connection(close), status(Code)], []) :-
http_header:status_number_fact(request_timeout, Code),
with_output_to(codes(MessageBytes),
json_write_dict(current_output,
_{
code: Code,
message: "Client took too long to send request body. Perhaps the Content-Length header is wrong."
})).
/* parse_error(Reason, Location) => bad request
*
* Client supplied JSON input which could not be parsed as
......
......@@ -20,6 +20,7 @@
% @throws invalid_header_value(content_length, Value) if a Content-Length header
% has been sent but the given value Value is invalid (no nonnegative
% integer).
% @throws `request_timeout` if reading the body timed out
read_json_body(Request, Payload) :-
( memberchk(content_length(Len), Request)
-> ( integer(Len),
......@@ -29,16 +30,29 @@ read_json_body(Request, Payload) :-
)
; throw(length_required)
),
catch(http_read_json_dict(Request, Payload, [value_string_as(atom)]),
error(syntax_error(json(Details)),
stream(_S, Line, LinePos, _CharNo)),
throw(parse_error(illegal_json_syntax(Details),
stream_position(Line, LinePos)))
)
read_json_body_(Request, Payload)
-> true
; throw(empty_request_body).
read_json_body_(Request, Payload) :-
catch(http_read_json_dict(Request, Payload, [value_string_as(atom)]),
Error, true),
( var(Error)
-> true
; Error = error(syntax_error(json(Details)),
stream(_S, Line, LinePos, _CharNo))
-> throw(parse_error(illegal_json_syntax(Details),
stream_position(Line, LinePos)))
; Error = error(timeout_error(read, _Stream),_)
-> throw(request_timeout)
; api_error(implementation_error,[
error(Error),
source(http_read_json_dict/3)
])
).
%! purge_input_stream(+Request) is det.
%
% Purge the content of the request body. Only possible if a
......@@ -48,6 +62,8 @@ read_json_body(Request, Payload) :-
% @throws invalid_header_value(content_length, Value) if a Content-Length header
% has been sent but the given value Value is invalid (no nonnegative
% integer).
% @throws `request_timeout` if discarded the body timed out (less bytes on the
% streem than promised by a Content-Length header).
purge_input_stream(Request) :-
memberchk(input(StreamIn), Request),
memberchk(content_length(Len), Request),
......@@ -55,13 +71,18 @@ purge_input_stream(Request) :-
integer(Len),
( Len >= 0
-> setup_call_cleanup(open_null_stream(StreamOut),
copy_stream_data(StreamIn, StreamOut, Len),
purge_input_stream_(StreamIn, StreamOut, Len),
close(StreamOut)
); throw(invalid_header_value(content_length, Len))
)
.
purge_input_stream(_).
purge_input_stream_(StreamIn, StreamOut, Len) :-
catch(copy_stream_data(StreamIn, StreamOut, Len),
error(timeout_error(read, _Stream),_),
throw(request_timeout)
).
%! parse_parameters(+In, ++Type, -Out) is det.
%
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment