/* * Copyright (c) 2018-2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace RequestServer::Detail { template void init(TSelf* self, TJob job) { job->on_headers_received = [self](auto& headers, auto response_code) { if (response_code.has_value()) self->set_status_code(response_code.value()); self->set_response_headers(headers); }; job->on_finish = [self](bool success) { Core::deferred_invoke([url = self->job().url(), socket = self->job().socket()] { ConnectionCache::request_did_finish(url, socket); }); if (auto* response = self->job().response()) { self->set_status_code(response->code()); self->set_response_headers(response->headers()); self->set_downloaded_size(response->downloaded_size()); } // if we didn't know the total size, pretend that the request finished successfully // and set the total size to the downloaded size if (!self->total_size().has_value()) self->did_progress(self->downloaded_size(), self->downloaded_size()); self->did_finish(success); }; job->on_progress = [self](Optional total, u32 current) { self->did_progress(total, current); }; if constexpr (requires { job->on_certificate_requested; }) { job->on_certificate_requested = [job, self] { self->did_request_certificates(); Core::EventLoop::current().spin_until([&] { return job->received_client_certificates(); }); return job->take_client_certificates(); }; } } template OwnPtr start_request(TBadgedProtocol&& protocol, ConnectionFromClient& client, String const& method, const URL& url, HashMap const& headers, ReadonlyBytes body, TPipeResult&& pipe_result, Core::ProxyData proxy_data = {}) { using TJob = typename TBadgedProtocol::Type::JobType; using TRequest = typename TBadgedProtocol::Type::RequestType; if (pipe_result.is_error()) { return {}; } HTTP::HttpRequest request; if (method.equals_ignoring_case("post"sv)) request.set_method(HTTP::HttpRequest::Method::POST); else if (method.equals_ignoring_case("head"sv)) request.set_method(HTTP::HttpRequest::Method::HEAD); else if (method.equals_ignoring_case("delete"sv)) request.set_method(HTTP::HttpRequest::Method::DELETE); else if (method.equals_ignoring_case("patch"sv)) request.set_method(HTTP::HttpRequest::Method::PATCH); else if (method.equals_ignoring_case("options"sv)) request.set_method(HTTP::HttpRequest::Method::OPTIONS); else if (method.equals_ignoring_case("trace"sv)) request.set_method(HTTP::HttpRequest::Method::TRACE); else if (method.equals_ignoring_case("connect"sv)) request.set_method(HTTP::HttpRequest::Method::CONNECT); else if (method.equals_ignoring_case("put"sv)) request.set_method(HTTP::HttpRequest::Method::PUT); else request.set_method(HTTP::HttpRequest::Method::GET); request.set_url(url); request.set_headers(headers); auto allocated_body_result = ByteBuffer::copy(body); if (allocated_body_result.is_error()) return {}; request.set_body(allocated_body_result.release_value()); auto output_stream = MUST(Core::Stream::File::adopt_fd(pipe_result.value().write_fd, Core::Stream::OpenMode::Write)); auto job = TJob::construct(move(request), *output_stream); auto protocol_request = TRequest::create_with_job(forward(protocol), client, (TJob&)*job, move(output_stream)); protocol_request->set_request_fd(pipe_result.value().read_fd); if constexpr (IsSame) ConnectionCache::get_or_create_connection(ConnectionCache::g_tls_connection_cache, url, *job, proxy_data); else ConnectionCache::get_or_create_connection(ConnectionCache::g_tcp_connection_cache, url, *job, proxy_data); return protocol_request; } }