GHttp: Work on bringing this up.

This commit is contained in:
Andreas Kling 2019-04-07 19:35:07 +02:00
parent 8f30657390
commit 51b4d3fe5a
9 changed files with 93 additions and 16 deletions

View file

@ -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*, ...);

View file

@ -92,13 +92,13 @@ ByteBuffer String::to_byte_buffer() const
return ByteBuffer::copy(reinterpret_cast<const byte*>(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

View file

@ -2,6 +2,7 @@
#include <LibGUI/GHttpResponse.h>
#include <LibGUI/GTCPSocket.h>
#include <stdio.h>
#include <unistd.h>
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<byte> 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));

View file

@ -2,6 +2,7 @@
#include <LibGUI/GNetworkJob.h>
#include <LibGUI/GHttpRequest.h>
#include <AK/HashMap.h>
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<String, String> m_headers;
};

View file

@ -1,8 +1,9 @@
#include <LibGUI/GHttpResponse.h>
GHttpResponse::GHttpResponse(int code, ByteBuffer&& payload)
GHttpResponse::GHttpResponse(int code, HashMap<String, String>&& headers, ByteBuffer&& payload)
: GNetworkResponse(move(payload))
, m_code(code)
, m_headers(move(headers))
{
}

View file

@ -7,16 +7,16 @@
class GHttpResponse : public GNetworkResponse {
public:
virtual ~GHttpResponse() override;
static Retained<GHttpResponse> create(int code, ByteBuffer&& payload)
static Retained<GHttpResponse> create(int code, HashMap<String, String>&& 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<String, String>& headers() const { return m_headers; }
private:
GHttpResponse(int code, ByteBuffer&&);
GHttpResponse(int code, HashMap<String, String>&&, ByteBuffer&&);
int m_code { 0 };
HashMap<String, String> m_headers;

View file

@ -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<byte> 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 { };
}

View file

@ -21,7 +21,7 @@ void GNetworkJob::did_finish(Retained<GNetworkResponse>&& 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);
}

View file

@ -11,6 +11,7 @@ public:
None,
ConnectionFailed,
TransmissionFailed,
ProtocolFailed,
};
virtual ~GNetworkJob() override;