mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 01:20:25 +00:00
CHttpJob: Drive response download via on_ready_read instead of blocking
This allows the event loop to service events while an HTTP download is happening. Pretty cool :^)
This commit is contained in:
parent
72b69b82bb
commit
b5aac9c44b
Notes:
sideshowbarker
2024-07-19 12:53:43 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/b5aac9c44be
2 changed files with 25 additions and 28 deletions
|
@ -24,14 +24,10 @@ void CHttpJob::on_socket_connected()
|
|||
if (!success)
|
||||
return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::TransmissionFailed); });
|
||||
|
||||
Vector<ByteBuffer> received_buffers;
|
||||
size_t received_size = 0;
|
||||
|
||||
while (m_socket->is_connected()) {
|
||||
m_socket->on_ready_to_read = [&] {
|
||||
if (m_state == State::InStatus) {
|
||||
while (!m_socket->can_read_line())
|
||||
usleep(1);
|
||||
ASSERT(m_socket->can_read_line());
|
||||
if (!m_socket->can_read_line())
|
||||
return;
|
||||
auto line = m_socket->read_line(PAGE_SIZE);
|
||||
if (line.is_null()) {
|
||||
printf("Expected HTTP status\n");
|
||||
|
@ -49,11 +45,11 @@ void CHttpJob::on_socket_connected()
|
|||
return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
m_state = State::InHeaders;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
if (m_state == State::InHeaders) {
|
||||
while (!m_socket->can_read_line())
|
||||
usleep(1);
|
||||
if (!m_socket->can_read_line())
|
||||
return;
|
||||
auto line = m_socket->read_line(PAGE_SIZE);
|
||||
if (line.is_null()) {
|
||||
printf("Expected HTTP header\n");
|
||||
|
@ -62,7 +58,7 @@ void CHttpJob::on_socket_connected()
|
|||
auto chomped_line = String::copy(line, Chomp);
|
||||
if (chomped_line.is_empty()) {
|
||||
m_state = State::InBody;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
auto parts = chomped_line.split(':');
|
||||
if (parts.is_empty()) {
|
||||
|
@ -77,40 +73,38 @@ void CHttpJob::on_socket_connected()
|
|||
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;
|
||||
return;
|
||||
}
|
||||
ASSERT(m_state == State::InBody);
|
||||
while (!m_socket->can_read())
|
||||
usleep(1);
|
||||
ASSERT(m_socket->can_read());
|
||||
auto payload = m_socket->receive(PAGE_SIZE);
|
||||
if (!payload) {
|
||||
if (m_socket->eof()) {
|
||||
m_state = State::Finished;
|
||||
break;
|
||||
}
|
||||
if (m_socket->eof())
|
||||
return finish_up();
|
||||
return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
received_buffers.append(payload);
|
||||
received_size += payload.size();
|
||||
m_received_buffers.append(payload);
|
||||
m_received_size += payload.size();
|
||||
|
||||
auto content_length_header = m_headers.get("Content-Length");
|
||||
if (content_length_header.has_value()) {
|
||||
bool ok;
|
||||
if (received_size >= content_length_header.value().to_uint(ok) && ok) {
|
||||
m_state = State::Finished;
|
||||
break;
|
||||
}
|
||||
if (m_received_size >= content_length_header.value().to_uint(ok) && ok)
|
||||
return finish_up();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
auto flattened_buffer = ByteBuffer::create_uninitialized(received_size);
|
||||
void CHttpJob::finish_up()
|
||||
{
|
||||
m_state = State::Finished;
|
||||
auto flattened_buffer = ByteBuffer::create_uninitialized(m_received_size);
|
||||
u8* flat_ptr = flattened_buffer.data();
|
||||
for (auto& received_buffer : received_buffers) {
|
||||
for (auto& received_buffer : m_received_buffers) {
|
||||
memcpy(flat_ptr, received_buffer.data(), received_buffer.size());
|
||||
flat_ptr += received_buffer.size();
|
||||
}
|
||||
received_buffers.clear();
|
||||
m_received_buffers.clear();
|
||||
|
||||
auto response = CHttpResponse::create(m_code, move(m_headers), move(flattened_buffer));
|
||||
deferred_invoke([this, response](auto&) {
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
private:
|
||||
void on_socket_connected();
|
||||
void finish_up();
|
||||
|
||||
enum class State {
|
||||
InStatus,
|
||||
|
@ -29,4 +30,6 @@ private:
|
|||
State m_state { State::InStatus };
|
||||
int m_code { -1 };
|
||||
HashMap<String, String> m_headers;
|
||||
Vector<ByteBuffer> m_received_buffers;
|
||||
size_t m_received_size { 0 };
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue