LibGemini: Do not loop in Gemini::Job in case of error

Previously, the job was shutdown only on a deferred invoke while there
was still data to be read. This meant that the read callback would get
called again and again, and, potentially throw the error again and again

This patch introoduces a failed state for the protocol parser and
returns early from the read callback if it has already failed
This commit is contained in:
Arda Cinar 2023-01-13 20:28:45 +03:00 committed by Andreas Kling
parent 083802d41a
commit ba9fa59355
Notes: sideshowbarker 2024-07-17 18:46:57 +09:00
2 changed files with 8 additions and 0 deletions

View file

@ -124,6 +124,8 @@ void Job::on_socket_connected()
register_on_ready_to_read([this] {
if (is_cancelled())
return;
if (m_state == State::Failed)
return;
if (m_state == State::InStatus) {
if (!can_read_line())
@ -132,6 +134,7 @@ void Job::on_socket_connected()
auto line_or_error = read_line(PAGE_SIZE);
if (line_or_error.is_error()) {
dbgln("Job: Error getting status line {}", line_or_error.error());
m_state = State::Failed;
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::TransmissionFailed); });
}
@ -141,6 +144,7 @@ void Job::on_socket_connected()
auto maybe_space_index = view.find(' ');
if (!maybe_space_index.has_value()) {
dbgln("Job: Expected 2-part status line, got '{}'", line);
m_state = State::Failed;
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
}
@ -151,6 +155,7 @@ void Job::on_socket_connected()
auto status = first_part.to_uint();
if (!status.has_value()) {
dbgln("Job: Expected numeric status code");
m_state = State::Failed;
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
}
@ -171,6 +176,7 @@ void Job::on_socket_connected()
m_state = State::InBody;
} else {
dbgln("Job: Expected status between 10 and 69; instead got {}", m_status);
m_state = State::Failed;
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
}
@ -188,6 +194,7 @@ void Job::on_socket_connected()
auto payload_or_error = receive(read_size);
if (payload_or_error.is_error()) {
dbgln("Job: Error in receive {}", payload_or_error.error());
m_state = State::Failed;
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::TransmissionFailed); });
}
auto payload = payload_or_error.release_value();

View file

@ -46,6 +46,7 @@ protected:
InStatus,
InBody,
Finished,
Failed,
};
GeminiRequest m_request;