mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-02 22:24:26 +00:00
LibIMAP: Wait for a full IMAP response before parsing
We're now sniffing the incoming data to verify the server has sent a full response, instead of passing partial data to our IMAP parser. Our parser really can't handle partial input very well, so for the time being, this heuristic does a much better job of verifying we have full response before parsing. It doesn't yet handle unprompted untagged reponses, nor the "continuation request" responses that start with a `+`, but we don't fully support those yet.
This commit is contained in:
parent
0b7e18177b
commit
34adf9eeae
|
@ -53,6 +53,26 @@ ErrorOr<NonnullOwnPtr<Client>> Client::connect_plaintext(StringView host, u16 po
|
|||
return adopt_nonnull_own_or_enomem(new (nothrow) Client(host, port, move(socket)));
|
||||
}
|
||||
|
||||
bool Client::verify_response_is_complete()
|
||||
{
|
||||
// FIXME: This is still more of a heuristic than a proper approach.
|
||||
// I would imagine this breaks if we happen to get an email that
|
||||
// contains this pattern we're looking for.
|
||||
dbgln("Waiting for a complete IMAP response, buffer size is now {}", m_buffer.size());
|
||||
Vector<StringView> statuses = { "OK"sv, "BAD"sv, "NO"sv };
|
||||
auto slice_size = m_buffer.size() >= 100 ? 100 : m_buffer.size(); // Arbitrary slice size, should contain what we're looking for.
|
||||
auto slice_data = MUST(m_buffer.slice(m_buffer.size() - slice_size, slice_size));
|
||||
StringView slice = StringView(slice_data);
|
||||
for (auto status : statuses) {
|
||||
DeprecatedString pattern = DeprecatedString::formatted("A{} {}", m_current_command, status);
|
||||
if (slice.contains(pattern)) {
|
||||
dbgln("IMAP server replied {}, sending to parser", pattern);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ErrorOr<void> Client::on_ready_to_receive()
|
||||
{
|
||||
if (!TRY(m_socket->can_read_without_blocking()))
|
||||
|
@ -70,8 +90,8 @@ ErrorOr<void> Client::on_ready_to_receive()
|
|||
return {};
|
||||
}
|
||||
|
||||
if (m_buffer[m_buffer.size() - 1] == '\n') {
|
||||
// Don't try parsing until we have a complete line.
|
||||
// Don't try parsing until we have a complete response.
|
||||
if (verify_response_is_complete()) {
|
||||
auto response = m_parser.parse(move(m_buffer), m_expecting_response);
|
||||
TRY(handle_parsed_response(move(response)));
|
||||
m_buffer.clear();
|
||||
|
|
|
@ -63,6 +63,7 @@ private:
|
|||
void setup_callbacks();
|
||||
|
||||
ErrorOr<void> on_ready_to_receive();
|
||||
bool verify_response_is_complete();
|
||||
|
||||
ErrorOr<void> handle_parsed_response(ParseStatus&& parse_status);
|
||||
ErrorOr<void> send_next_command();
|
||||
|
|
Loading…
Reference in a new issue