From 51b4d3fe5a97dad8c2d701bed214741a200c5c70 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 7 Apr 2019 19:35:07 +0200 Subject: [PATCH] GHttp: Work on bringing this up. --- AK/AKString.h | 2 +- AK/String.cpp | 4 +-- LibGUI/GHttpNetworkJob.cpp | 63 +++++++++++++++++++++++++++++++++++--- LibGUI/GHttpNetworkJob.h | 11 +++++++ LibGUI/GHttpResponse.cpp | 3 +- LibGUI/GHttpResponse.h | 6 ++-- LibGUI/GIODevice.cpp | 17 +++++++--- LibGUI/GNetworkJob.cpp | 2 +- LibGUI/GNetworkJob.h | 1 + 9 files changed, 93 insertions(+), 16 deletions(-) diff --git a/AK/AKString.h b/AK/AKString.h index 65abb9e10f..4f9b8ec84a 100644 --- a/AK/AKString.h +++ b/AK/AKString.h @@ -102,7 +102,7 @@ public: } ByteBuffer to_byte_buffer() const; - static String from_byte_buffer(const ByteBuffer&); + static String from_byte_buffer(const ByteBuffer&, ShouldChomp = NoChomp); static String format(const char*, ...); diff --git a/AK/String.cpp b/AK/String.cpp index 5892e7ee5e..e6411384d6 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -92,13 +92,13 @@ ByteBuffer String::to_byte_buffer() const return ByteBuffer::copy(reinterpret_cast(characters()), length()); } -String String::from_byte_buffer(const ByteBuffer& buffer) +String String::from_byte_buffer(const ByteBuffer& buffer, ShouldChomp should_chomp) { if (buffer.is_null()) return nullptr; if (buffer.is_empty()) return empty(); - return String((const char*)buffer.pointer(), buffer.size()); + return String((const char*)buffer.pointer(), buffer.size(), should_chomp); } unsigned String::to_uint(bool& ok) const diff --git a/LibGUI/GHttpNetworkJob.cpp b/LibGUI/GHttpNetworkJob.cpp index 789ad70c5d..87ca325663 100644 --- a/LibGUI/GHttpNetworkJob.cpp +++ b/LibGUI/GHttpNetworkJob.cpp @@ -2,6 +2,7 @@ #include #include #include +#include GHttpNetworkJob::GHttpNetworkJob(const GHttpRequest& request) : m_request(request) @@ -26,20 +27,74 @@ void GHttpNetworkJob::start() success = m_socket->send(raw_request); if (!success) - return did_fail(GNetworkJob::Error::TransmissionFailed); + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::TransmissionFailed); }); Vector buffer; while (m_socket->is_connected()) { + if (m_state == State::InStatus) { + while (!m_socket->can_read_line()) + usleep(1); + ASSERT(m_socket->can_read_line()); + auto line = m_socket->read_line(1024); + if (line.is_null()) { + printf("Expected HTTP status\n"); + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::TransmissionFailed); }); + } + auto parts = String::from_byte_buffer(line, Chomp).split(' '); + if (parts.size() < 3) { + printf("Expected 3-part HTTP status, got '%s'\n", line.pointer()); + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); }); + } + bool ok; + m_code = parts[1].to_uint(ok); + if (!ok) { + printf("Expected numeric HTTP status\n"); + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); }); + } + m_state = State::InHeaders; + continue; + } + if (m_state == State::InHeaders) { + while (!m_socket->can_read_line()) + usleep(1); + auto line = m_socket->read_line(1024); + if (line.is_null()) { + printf("Expected HTTP header\n"); + return did_fail(GNetworkJob::Error::ProtocolFailed); + } + auto chomped_line = String::from_byte_buffer(line, Chomp); + if (chomped_line.is_empty()) { + m_state = State::InBody; + continue; + } + auto parts = chomped_line.split(':'); + if (parts.is_empty()) { + printf("Expected HTTP header with key/value\n"); + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); }); + } + auto name = parts[0]; + if (chomped_line.length() < name.length() + 2) { + printf("Malformed HTTP header\n"); + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); }); + } + auto value = chomped_line.substring(name.length() + 2, line.size() - name.length() - 2); + m_headers.set(name, value); + printf("[%s] = '%s'\n", name.characters(), value.characters()); + continue; + } + ASSERT(m_state == State::InBody); auto payload = m_socket->receive(100000); if (!payload) { - if (m_socket->eof()) + if (m_socket->eof()) { + m_state = State::Finished; break; - return did_fail(GNetworkJob::Error::TransmissionFailed); + } + return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); }); } buffer.append(payload.pointer(), payload.size()); } - auto response = GHttpResponse::create(1, ByteBuffer::copy(buffer.data(), buffer.size())); + auto response = GHttpResponse::create(m_code, move(m_headers), ByteBuffer::copy(buffer.data(), buffer.size())); deferred_invoke([this, response] (GObject&) { printf("in the deferred invoke lambda\n"); did_finish(move(response)); diff --git a/LibGUI/GHttpNetworkJob.h b/LibGUI/GHttpNetworkJob.h index f7d86f1eaa..8abf7dff49 100644 --- a/LibGUI/GHttpNetworkJob.h +++ b/LibGUI/GHttpNetworkJob.h @@ -2,6 +2,7 @@ #include #include +#include class GTCPSocket; @@ -15,6 +16,16 @@ public: virtual const char* class_name() const override { return "GHttpNetworkJob"; } private: + enum class State { + InStatus, + InHeaders, + InBody, + Finished, + }; + GHttpRequest m_request; GTCPSocket* m_socket { nullptr }; + State m_state { State::InStatus }; + int m_code { -1 }; + HashMap m_headers; }; diff --git a/LibGUI/GHttpResponse.cpp b/LibGUI/GHttpResponse.cpp index 888432f9af..95f01c80f5 100644 --- a/LibGUI/GHttpResponse.cpp +++ b/LibGUI/GHttpResponse.cpp @@ -1,8 +1,9 @@ #include -GHttpResponse::GHttpResponse(int code, ByteBuffer&& payload) +GHttpResponse::GHttpResponse(int code, HashMap&& headers, ByteBuffer&& payload) : GNetworkResponse(move(payload)) , m_code(code) + , m_headers(move(headers)) { } diff --git a/LibGUI/GHttpResponse.h b/LibGUI/GHttpResponse.h index b6bb702b26..52f90e52ac 100644 --- a/LibGUI/GHttpResponse.h +++ b/LibGUI/GHttpResponse.h @@ -7,16 +7,16 @@ class GHttpResponse : public GNetworkResponse { public: virtual ~GHttpResponse() override; - static Retained create(int code, ByteBuffer&& payload) + static Retained create(int code, HashMap&& headers, ByteBuffer&& payload) { - return adopt(*new GHttpResponse(code, move(payload))); + return adopt(*new GHttpResponse(code, move(headers), move(payload))); } int code() const { return m_code; } const HashMap& headers() const { return m_headers; } private: - GHttpResponse(int code, ByteBuffer&&); + GHttpResponse(int code, HashMap&&, ByteBuffer&&); int m_code { 0 }; HashMap m_headers; diff --git a/LibGUI/GIODevice.cpp b/LibGUI/GIODevice.cpp index 19a8497c8d..35e042b2cc 100644 --- a/LibGUI/GIODevice.cpp +++ b/LibGUI/GIODevice.cpp @@ -109,15 +109,21 @@ ByteBuffer GIODevice::read_all() ByteBuffer GIODevice::read_line(int max_size) { - if (m_fd < 0) + if (m_fd < 0) { + printf("nofd\n"); return { }; - if (!max_size) + } + if (!max_size) { + printf("noms\n"); return { }; - if (!can_read_line()) + } + if (!can_read_line()) { + printf("norl\n"); return { }; + } if (m_eof) { if (m_buffered_data.size() > max_size) { - dbgprintf("GIODevice::read_line: At EOF but there's more than max_size(%d) buffered\n", max_size); + printf("GIODevice::read_line: At EOF but there's more than max_size(%d) buffered\n", max_size); return { }; } auto buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size()); @@ -128,6 +134,7 @@ ByteBuffer GIODevice::read_line(int max_size) int line_index = 0; while (line_index < max_size) { byte ch = m_buffered_data[line_index]; + printf("%c", ch); line[line_index++] = ch; if (ch == '\n') { Vector new_buffered_data; @@ -135,9 +142,11 @@ ByteBuffer GIODevice::read_line(int max_size) m_buffered_data = move(new_buffered_data); line[line_index] = '\0'; line.trim(line_index + 1); + printf("\n"); return line; } } + printf("\nnowork\n"); return { }; } diff --git a/LibGUI/GNetworkJob.cpp b/LibGUI/GNetworkJob.cpp index fa002ef214..fb473a7c0e 100644 --- a/LibGUI/GNetworkJob.cpp +++ b/LibGUI/GNetworkJob.cpp @@ -21,7 +21,7 @@ void GNetworkJob::did_finish(Retained&& response) void GNetworkJob::did_fail(Error error) { m_error = error; - dbgprintf("%s{%} job did_fail! error=%u\n", class_name(), this, (unsigned)error); + dbgprintf("%s{%p} job did_fail! error=%u\n", class_name(), this, (unsigned)error); ASSERT(on_finish); on_finish(false); } diff --git a/LibGUI/GNetworkJob.h b/LibGUI/GNetworkJob.h index 217e29dc68..fcabcd34be 100644 --- a/LibGUI/GNetworkJob.h +++ b/LibGUI/GNetworkJob.h @@ -11,6 +11,7 @@ public: None, ConnectionFailed, TransmissionFailed, + ProtocolFailed, }; virtual ~GNetworkJob() override;