mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:17:36 +00:00
LibHTTP+WebDriver+WebServer: Return error from HTTP request parser
This commit is contained in:
parent
5b31d1208f
commit
9220cdc285
6 changed files with 35 additions and 13 deletions
|
@ -11,7 +11,7 @@
|
||||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||||
{
|
{
|
||||||
auto request_wrapper = HTTP::HttpRequest::from_raw_request(ReadonlyBytes { data, size });
|
auto request_wrapper = HTTP::HttpRequest::from_raw_request(ReadonlyBytes { data, size });
|
||||||
if (!request_wrapper.has_value())
|
if (!request_wrapper.is_error())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto& request = request_wrapper.value();
|
auto& request = request_wrapper.value();
|
||||||
|
|
|
@ -75,7 +75,7 @@ ErrorOr<ByteBuffer> HttpRequest::to_raw_request() const
|
||||||
return builder.to_byte_buffer();
|
return builder.to_byte_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<HttpRequest> HttpRequest::from_raw_request(ReadonlyBytes raw_request)
|
ErrorOr<HttpRequest, HttpRequest::ParseError> HttpRequest::from_raw_request(ReadonlyBytes raw_request)
|
||||||
{
|
{
|
||||||
enum class State {
|
enum class State {
|
||||||
InMethod,
|
InMethod,
|
||||||
|
@ -118,7 +118,7 @@ Optional<HttpRequest> HttpRequest::from_raw_request(ReadonlyBytes raw_request)
|
||||||
while (index < raw_request.size()) {
|
while (index < raw_request.size()) {
|
||||||
// FIXME: Figure out what the appropriate limitations should be.
|
// FIXME: Figure out what the appropriate limitations should be.
|
||||||
if (buffer.size() > 65536)
|
if (buffer.size() > 65536)
|
||||||
return {};
|
return ParseError::RequestTooLarge;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State::InMethod:
|
case State::InMethod:
|
||||||
if (peek() == ' ') {
|
if (peek() == ' ') {
|
||||||
|
@ -178,9 +178,10 @@ Optional<HttpRequest> HttpRequest::from_raw_request(ReadonlyBytes raw_request)
|
||||||
if (index == raw_request.size()) {
|
if (index == raw_request.size()) {
|
||||||
// End of data, so store the body
|
// End of data, so store the body
|
||||||
auto maybe_body = ByteBuffer::copy(buffer);
|
auto maybe_body = ByteBuffer::copy(buffer);
|
||||||
// FIXME: Propagate this error somehow.
|
if (maybe_body.is_error()) {
|
||||||
if (maybe_body.is_error())
|
VERIFY(maybe_body.error().code() == ENOMEM);
|
||||||
return {};
|
return ParseError::OutOfMemory;
|
||||||
|
}
|
||||||
body = maybe_body.release_value();
|
body = maybe_body.release_value();
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
|
@ -208,7 +209,7 @@ Optional<HttpRequest> HttpRequest::from_raw_request(ReadonlyBytes raw_request)
|
||||||
else if (method == "PUT")
|
else if (method == "PUT")
|
||||||
request.set_method(HTTP::HttpRequest::Method::PUT);
|
request.set_method(HTTP::HttpRequest::Method::PUT);
|
||||||
else
|
else
|
||||||
return {};
|
return ParseError::UnsupportedMethod;
|
||||||
|
|
||||||
request.m_headers = move(headers);
|
request.m_headers = move(headers);
|
||||||
auto url_parts = resource.split_limit('?', 2, SplitBehavior::KeepEmpty);
|
auto url_parts = resource.split_limit('?', 2, SplitBehavior::KeepEmpty);
|
||||||
|
|
|
@ -18,6 +18,26 @@ namespace HTTP {
|
||||||
|
|
||||||
class HttpRequest {
|
class HttpRequest {
|
||||||
public:
|
public:
|
||||||
|
enum class ParseError {
|
||||||
|
RequestTooLarge,
|
||||||
|
OutOfMemory,
|
||||||
|
UnsupportedMethod
|
||||||
|
};
|
||||||
|
|
||||||
|
static StringView parse_error_to_string(ParseError error)
|
||||||
|
{
|
||||||
|
switch (error) {
|
||||||
|
case ParseError::RequestTooLarge:
|
||||||
|
return "Request too large"sv;
|
||||||
|
case ParseError::OutOfMemory:
|
||||||
|
return "Out of memory"sv;
|
||||||
|
case ParseError::UnsupportedMethod:
|
||||||
|
return "Unsupported method"sv;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum Method {
|
enum Method {
|
||||||
Invalid,
|
Invalid,
|
||||||
HEAD,
|
HEAD,
|
||||||
|
@ -61,7 +81,7 @@ public:
|
||||||
|
|
||||||
void set_headers(HashMap<DeprecatedString, DeprecatedString> const&);
|
void set_headers(HashMap<DeprecatedString, DeprecatedString> const&);
|
||||||
|
|
||||||
static Optional<HttpRequest> from_raw_request(ReadonlyBytes);
|
static ErrorOr<HttpRequest, HttpRequest::ParseError> from_raw_request(ReadonlyBytes);
|
||||||
static Optional<Header> get_http_basic_authentication_header(URL const&);
|
static Optional<Header> get_http_basic_authentication_header(URL const&);
|
||||||
static Optional<BasicAuthenticationCredentials> parse_http_basic_authentication_header(DeprecatedString const&);
|
static Optional<BasicAuthenticationCredentials> parse_http_basic_authentication_header(DeprecatedString const&);
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,9 @@ Client::Client(NonnullOwnPtr<Core::BufferedTCPSocket> socket, Core::Object* pare
|
||||||
[](AK::Error const& error) {
|
[](AK::Error const& error) {
|
||||||
warnln("Internal error: {}", error);
|
warnln("Internal error: {}", error);
|
||||||
},
|
},
|
||||||
|
[](HTTP::HttpRequest::ParseError const& error) {
|
||||||
|
warnln("HTTP request parsing error: {}", HTTP::HttpRequest::parse_error_to_string(error));
|
||||||
|
},
|
||||||
[this](WebDriver::Error const& error) {
|
[this](WebDriver::Error const& error) {
|
||||||
if (send_error_response(error).is_error())
|
if (send_error_response(error).is_error())
|
||||||
warnln("Could not send error response");
|
warnln("Could not send error response");
|
||||||
|
@ -221,9 +224,7 @@ ErrorOr<void, Client::WrappedError> Client::on_ready_to_read()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_request = HTTP::HttpRequest::from_raw_request(TRY(builder.to_byte_buffer()));
|
m_request = TRY(HTTP::HttpRequest::from_raw_request(TRY(builder.to_byte_buffer())));
|
||||||
if (!m_request.has_value())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
auto body = TRY(read_body_as_json());
|
auto body = TRY(read_body_as_json());
|
||||||
TRY(handle_request(move(body)));
|
TRY(handle_request(move(body)));
|
||||||
|
|
|
@ -109,7 +109,7 @@ protected:
|
||||||
Client(NonnullOwnPtr<Core::BufferedTCPSocket>, Core::Object* parent);
|
Client(NonnullOwnPtr<Core::BufferedTCPSocket>, Core::Object* parent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using WrappedError = Variant<AK::Error, WebDriver::Error>;
|
using WrappedError = Variant<AK::Error, HTTP::HttpRequest::ParseError, WebDriver::Error>;
|
||||||
|
|
||||||
void die();
|
void die();
|
||||||
ErrorOr<void, WrappedError> on_ready_to_read();
|
ErrorOr<void, WrappedError> on_ready_to_read();
|
||||||
|
|
|
@ -97,7 +97,7 @@ void Client::start()
|
||||||
ErrorOr<bool> Client::handle_request(ReadonlyBytes raw_request)
|
ErrorOr<bool> Client::handle_request(ReadonlyBytes raw_request)
|
||||||
{
|
{
|
||||||
auto request_or_error = HTTP::HttpRequest::from_raw_request(raw_request);
|
auto request_or_error = HTTP::HttpRequest::from_raw_request(raw_request);
|
||||||
if (!request_or_error.has_value())
|
if (request_or_error.is_error())
|
||||||
return false;
|
return false;
|
||||||
auto& request = request_or_error.value();
|
auto& request = request_or_error.value();
|
||||||
auto resource_decoded = URL::percent_decode(request.resource());
|
auto resource_decoded = URL::percent_decode(request.resource());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue