diff --git a/Tests/LibTLS/TestTLSHandshake.cpp b/Tests/LibTLS/TestTLSHandshake.cpp index 4cdc6bcd19..2f42c29fbb 100644 --- a/Tests/LibTLS/TestTLSHandshake.cpp +++ b/Tests/LibTLS/TestTLSHandshake.cpp @@ -61,11 +61,7 @@ TEST_CASE(test_TLS_hello_handshake) auto tls = TRY_OR_FAIL(TLS::TLSv12::connect(DEFAULT_SERVER, port, move(options))); ByteBuffer contents; tls->on_ready_to_read = [&] { - auto read_bytes = TRY_OR_FAIL(tls->read_some(contents.must_get_bytes_for_writing(4 * KiB))); - if (read_bytes.is_empty()) { - FAIL("No data received"); - loop.quit(1); - } + (void)TRY_OR_FAIL(tls->read_some(contents.must_get_bytes_for_writing(4 * KiB))); loop.quit(0); }; diff --git a/Userland/Libraries/LibHTTP/Job.cpp b/Userland/Libraries/LibHTTP/Job.cpp index f157dd723a..d038c38999 100644 --- a/Userland/Libraries/LibHTTP/Job.cpp +++ b/Userland/Libraries/LibHTTP/Job.cpp @@ -223,8 +223,20 @@ void Job::on_socket_connected() } if (m_socket->is_eof()) { - dbgln_if(JOB_DEBUG, "Read failure: Actually EOF!"); - return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); }); + // Some servers really like terminating connections by simply closing them (even TLS ones) + // to signal end-of-data, if there's no: + // - connection + // - content-size + // - transfer-encoding: chunked + // header, simply treat EOF as a termination signal. + if (m_headers.contains("connection"sv) || m_content_length.has_value() || m_current_chunk_total_size.has_value()) { + dbgln_if(JOB_DEBUG, "Read failure: Actually EOF!"); + deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); }); + return; + } + + finish_up(); + return; } while (m_state == State::InStatus) { diff --git a/Userland/Libraries/LibTLS/Socket.cpp b/Userland/Libraries/LibTLS/Socket.cpp index 90febf9928..9e13824eb9 100644 --- a/Userland/Libraries/LibTLS/Socket.cpp +++ b/Userland/Libraries/LibTLS/Socket.cpp @@ -174,6 +174,16 @@ ErrorOr TLSv12::read_from_socket() consume(read_bytes); } while (!read_bytes.is_empty() && !m_context.critical_error); + if (read_bytes.is_empty()) { + // read_some() returned an empty span, this is either an EOF (from improper closure) + // or some sort of weird even that is showing itself as an EOF. + // To guard against servers closing the connection weirdly or just improperly, make sure + // to check the connection state here and send the appropriate notifications. + stream.close(); + + check_connection_state(true); + } + return {}; } @@ -204,6 +214,11 @@ bool TLSv12::check_connection_state(bool read) m_context.connection_finished = true; m_context.connection_status = ConnectionStatus::Disconnected; close(); + m_context.has_invoked_finish_or_error_callback = true; + if (on_ready_to_read) + on_ready_to_read(); // Notify the client about the weird event. + if (on_tls_finished) + on_tls_finished(); return false; } @@ -291,7 +306,8 @@ ErrorOr TLSv12::flush() void TLSv12::close() { - alert(AlertLevel::FATAL, AlertDescription::CLOSE_NOTIFY); + if (underlying_stream().is_open()) + alert(AlertLevel::FATAL, AlertDescription::CLOSE_NOTIFY); // bye bye. m_context.connection_status = ConnectionStatus::Disconnected; }