1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 03:57:44 +00:00

LibCore: Move HTTP classes from LibGUI to LibCore.

This commit is contained in:
Andreas Kling 2019-04-10 22:28:10 +02:00
parent cfd6e6cc36
commit ab1c84cf53
15 changed files with 92 additions and 93 deletions

View file

@ -1,109 +0,0 @@
#include <LibGUI/GHttpJob.h>
#include <LibGUI/GHttpResponse.h>
#include <LibCore/CTCPSocket.h>
#include <stdio.h>
#include <unistd.h>
GHttpJob::GHttpJob(const GHttpRequest& request)
: m_request(request)
{
}
GHttpJob::~GHttpJob()
{
}
void GHttpJob::on_socket_connected()
{
auto raw_request = m_request.to_raw_request();
#if 0
printf("raw_request:\n%s\n", String::from_byte_buffer(raw_request).characters());
#endif
bool success = m_socket->send(raw_request);
if (!success)
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(PAGE_SIZE);
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(PAGE_SIZE);
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: '%s' (%d)\n", chomped_line.characters(), chomped_line.length());
return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); });
}
auto value = chomped_line.substring(name.length() + 2, chomped_line.length() - 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(PAGE_SIZE);
if (!payload) {
if (m_socket->eof()) {
m_state = State::Finished;
break;
}
return deferred_invoke([this](auto&){ did_fail(GNetworkJob::Error::ProtocolFailed); });
}
buffer.append(payload.pointer(), payload.size());
}
auto response = GHttpResponse::create(m_code, move(m_headers), ByteBuffer::copy(buffer.data(), buffer.size()));
deferred_invoke([this, response] (auto&) {
did_finish(move(response));
});
}
void GHttpJob::start()
{
ASSERT(!m_socket);
m_socket = new CTCPSocket(this);
m_socket->on_connected = [this] {
printf("Socket on_connected callback\n");
on_socket_connected();
};
bool success = m_socket->connect(m_request.hostname(), m_request.port());
if (!success)
return did_fail(GNetworkJob::Error::ConnectionFailed);
}

View file

@ -1,33 +0,0 @@
#pragma once
#include <LibGUI/GNetworkJob.h>
#include <LibGUI/GHttpRequest.h>
#include <AK/HashMap.h>
class CTCPSocket;
class GHttpJob final : public GNetworkJob {
public:
explicit GHttpJob(const GHttpRequest&);
virtual ~GHttpJob() override;
virtual void start() override;
virtual const char* class_name() const override { return "GHttpJob"; }
private:
void on_socket_connected();
enum class State {
InStatus,
InHeaders,
InBody,
Finished,
};
GHttpRequest m_request;
CTCPSocket* m_socket { nullptr };
State m_state { State::InStatus };
int m_code { -1 };
HashMap<String, String> m_headers;
};

View file

@ -1,45 +0,0 @@
#include <LibGUI/GHttpRequest.h>
#include <LibGUI/GHttpJob.h>
#include <LibGUI/GEventLoop.h>
#include <AK/StringBuilder.h>
GHttpRequest::GHttpRequest()
{
}
GHttpRequest::~GHttpRequest()
{
}
GNetworkJob* GHttpRequest::schedule()
{
auto* job = new GHttpJob(*this);
job->start();
return job;
}
String GHttpRequest::method_name() const
{
switch (m_method) {
case Method::GET:
return "GET";
case Method::HEAD:
return "HEAD";
case Method::POST:
return "POST";
default:
ASSERT_NOT_REACHED();
}
}
ByteBuffer GHttpRequest::to_raw_request() const
{
StringBuilder builder;
builder.append(method_name());
builder.append(' ');
builder.append(m_path);
builder.append(" HTTP/1.0\nHost: ");
builder.append(m_hostname);
builder.append("\n\n");
return builder.to_byte_buffer();
}

View file

@ -1,34 +0,0 @@
#pragma once
#include <AK/AKString.h>
class GNetworkJob;
class GHttpRequest {
public:
enum Method { Invalid, HEAD, GET, POST };
GHttpRequest();
~GHttpRequest();
String hostname() const { return m_hostname; }
int port() const { return m_port; }
String path() const { return m_path; }
Method method() const { return m_method; }
void set_hostname(const String& hostname) { m_hostname = hostname; }
void set_port(int port) { m_port = port; }
void set_path(const String& path) { m_path = path; }
void set_method(Method method) { m_method = method; }
String method_name() const;
ByteBuffer to_raw_request() const;
GNetworkJob* schedule();
private:
String m_hostname;
String m_path;
int m_port { 80 };
Method m_method { GET };
};

View file

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

View file

@ -1,23 +0,0 @@
#pragma once
#include <LibGUI/GNetworkResponse.h>
#include <AK/AKString.h>
#include <AK/HashMap.h>
class GHttpResponse : public GNetworkResponse {
public:
virtual ~GHttpResponse() override;
static Retained<GHttpResponse> create(int code, HashMap<String, String>&& headers, ByteBuffer&& 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, HashMap<String, String>&&, ByteBuffer&&);
int m_code { 0 };
HashMap<String, String> m_headers;
};

View file

@ -1,27 +0,0 @@
#include <LibGUI/GNetworkJob.h>
#include <LibGUI/GNetworkResponse.h>
#include <stdio.h>
GNetworkJob::GNetworkJob()
{
}
GNetworkJob::~GNetworkJob()
{
}
void GNetworkJob::did_finish(Retained<GNetworkResponse>&& response)
{
m_response = move(response);
printf("%s{%p} job did_finish!\n", class_name(), this);
ASSERT(on_finish);
on_finish(true);
}
void GNetworkJob::did_fail(Error error)
{
m_error = error;
dbgprintf("%s{%p} job did_fail! error=%u\n", class_name(), this, (unsigned)error);
ASSERT(on_finish);
on_finish(false);
}

View file

@ -1,37 +0,0 @@
#pragma once
#include <LibCore/CObject.h>
#include <AK/Function.h>
class GNetworkResponse;
class GNetworkJob : public CObject {
public:
enum class Error {
None,
ConnectionFailed,
TransmissionFailed,
ProtocolFailed,
};
virtual ~GNetworkJob() override;
Function<void(bool success)> on_finish;
bool has_error() const { return m_error != Error::None; }
Error error() const { return m_error; }
GNetworkResponse* response() { return m_response.ptr(); }
const GNetworkResponse* response() const { return m_response.ptr(); }
virtual void start() = 0;
virtual const char* class_name() const override { return "GNetworkJob"; }
protected:
GNetworkJob();
void did_finish(Retained<GNetworkResponse>&&);
void did_fail(Error);
private:
RetainPtr<GNetworkResponse> m_response;
Error m_error { Error::None };
};

View file

@ -1,10 +0,0 @@
#include <LibGUI/GNetworkResponse.h>
GNetworkResponse::GNetworkResponse(ByteBuffer&& payload)
: m_payload(payload)
{
}
GNetworkResponse::~GNetworkResponse()
{
}

View file

@ -1,18 +0,0 @@
#pragma once
#include <AK/Retainable.h>
#include <AK/ByteBuffer.h>
class GNetworkResponse : public Retainable<GNetworkResponse> {
public:
virtual ~GNetworkResponse();
bool is_error() const { return m_error; }
const ByteBuffer& payload() const { return m_payload; }
protected:
explicit GNetworkResponse(ByteBuffer&&);
bool m_error { false };
ByteBuffer m_payload;
};

View file

@ -50,11 +50,6 @@ LIBGUI_OBJS = \
GFileSystemModel.o \
GSplitter.o \
GTimer.o \
GNetworkJob.o \
GNetworkResponse.o \
GHttpRequest.o \
GHttpResponse.o \
GHttpJob.o \
GSpinBox.o \
GGroupBox.o \
GWindow.o