mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 04:13:11 +00:00
GHttp: Work on bringing this up.
This commit is contained in:
parent
8f30657390
commit
51b4d3fe5a
|
@ -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*, ...);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 { };
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ public:
|
|||
None,
|
||||
ConnectionFailed,
|
||||
TransmissionFailed,
|
||||
ProtocolFailed,
|
||||
};
|
||||
virtual ~GNetworkJob() override;
|
||||
|
||||
|
|
Loading…
Reference in a new issue