Repository: LadybirdBrowser/ladybird
File: Services/RequestServer/Request.cpp (C++)

Code before:
    auto& request = *static_cast<Request*>(user_data);
    request.transfer_headers_to_client_if_needed();

    auto total_size = size * nmemb;
    ReadonlyBytes bytes { static_cast<u8 const*>(buffer), total_size };

    auto result = [&] -> ErrorOr<void> {
        TRY(request.m_response_buffer.write_some(bytes));
        return request.write_queued_bytes_without_blocking();
    }();

    if (result.is_error()) {
        dbgln("Request::on_data_received: Aborting request because error occurred whilst writing data to the client: {}", result.error());
        return CURL_WRITEFUNC_ERROR;
    }

    return total_size;
}

int Request::client_writer_fd() const
{
    VERIFY(m_client_request_pipe);
    return m_client_request_pipe->writer_fd();
}

ErrorOr<ssize_t> Request::write_bytes_to_client(Vector<u8> const& bytes) const
{
    VERIFY(m_client_request_pipe);
    return m_client_request_pipe->write(bytes);
}

void Request::transfer_headers_to_client_if_needed()
{
    if (exchange(m_sent_response_headers_to_client, true))
        return;

    m_status_code = acquire_status_code();
    m_client.async_headers_became_available(m_request_id, m_response_headers, m_status_code, m_reason_phrase);

    if (m_cache_entry_writer.has_value()) {
        if (m_cache_entry_writer->write_headers(m_status_code, m_reason_phrase, m_response_headers).is_error())
            m_cache_entry_writer.clear();
    }
}

ErrorOr<void> Request::write_queued_bytes_without_blocking()
{
    auto available_bytes = m_response_buffer.used_buffer_size();

    // If we've received a response to a range request that is not the partial content (206) we requested, we must
    // only transfer the subset of data that WebContent now needs. We discard all received bytes up to the expected

Review comment (suggestion):
Same here re: `ReadonlyBytes`.

Though I reckon we don't need either of these methods if we just keep `RequestPipe` on the stack. We can just have an `Optional<RequestPipe>` I think.

Code after:
    request.transfer_headers_to_client_if_needed();

    auto total_size = size * nmemb;
    ReadonlyBytes bytes { static_cast<u8 const*>(buffer), total_size };

    auto result = [&] -> ErrorOr<void> {
        TRY(request.m_response_buffer.write_some(bytes));
        return request.write_queued_bytes_without_blocking();
    }();

    if (result.is_error()) {
        dbgln("Request::on_data_received: Aborting request because error occurred whilst writing data to the client: {}", result.error());
        return CURL_WRITEFUNC_ERROR;
    }

    return total_size;
}

void Request::transfer_headers_to_client_if_needed()
{
    if (exchange(m_sent_response_headers_to_client, true))
        return;

    m_status_code = acquire_status_code();
    m_client.async_headers_became_available(m_request_id, m_response_headers, m_status_code, m_reason_phrase);

    if (m_cache_entry_writer.has_value()) {
        if (m_cache_entry_writer->write_headers(m_status_code, m_reason_phrase, m_response_headers).is_error())
            m_cache_entry_writer.clear();
    }
}

ErrorOr<void> Request::write_queued_bytes_without_blocking()
{
    auto available_bytes = m_response_buffer.used_buffer_size();

    // If we've received a response to a range request that is not the partial content (206) we requested, we must
    // only transfer the subset of data that WebContent now needs. We discard all received bytes up to the expected
    // start of the remaining data, and then transfer the remaining bytes.
    if (m_start_offset_of_response_resumed_from_cache.has_value()) {
        if (m_status_code == 206) {
            m_start_offset_of_response_resumed_from_cache.clear();
        } else if (m_status_code == 200) {
            // All bytes currently available have already been transferred. Discard them entirely.
            if (m_bytes_transferred_to_client + available_bytes <= *m_start_offset_of_response_resumed_from_cache) {
                m_bytes_transferred_to_client += available_bytes;

                MUST(m_response_buffer.discard(available_bytes));
                return {};
            }