Serenity Operating System
1/*
2 * Copyright (c) 2020-2022, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/HashMap.h>
10#include <AK/Optional.h>
11#include <LibCore/NetworkJob.h>
12#include <LibCore/Socket.h>
13#include <LibHTTP/HttpRequest.h>
14#include <LibHTTP/HttpResponse.h>
15
16namespace HTTP {
17
18class Job : public Core::NetworkJob {
19 C_OBJECT(Job);
20
21public:
22 explicit Job(HttpRequest&&, Stream&);
23 virtual ~Job() override = default;
24
25 virtual void start(Core::Socket&) override;
26 virtual void shutdown(ShutdownMode) override;
27
28 Core::Socket const* socket() const { return m_socket; }
29 URL url() const { return m_request.url(); }
30
31 HttpResponse* response() { return static_cast<HttpResponse*>(Core::NetworkJob::response()); }
32 HttpResponse const* response() const { return static_cast<HttpResponse const*>(Core::NetworkJob::response()); }
33
34protected:
35 void finish_up();
36 void on_socket_connected();
37 void flush_received_buffers();
38 void register_on_ready_to_read(Function<void()>);
39 ErrorOr<DeprecatedString> read_line(size_t);
40 ErrorOr<ByteBuffer> receive(size_t);
41 void timer_event(Core::TimerEvent&) override;
42
43 enum class State {
44 InStatus,
45 InHeaders,
46 InBody,
47 Trailers,
48 Finished,
49 };
50
51 HttpRequest m_request;
52 State m_state { State::InStatus };
53 Core::BufferedSocketBase* m_socket { nullptr };
54 bool m_legacy_connection { false };
55 int m_code { -1 };
56 HashMap<DeprecatedString, DeprecatedString, CaseInsensitiveStringTraits> m_headers;
57 Vector<DeprecatedString> m_set_cookie_headers;
58
59 struct ReceivedBuffer {
60 ReceivedBuffer(ByteBuffer d)
61 : data(move(d))
62 , pending_flush(data.bytes())
63 {
64 }
65
66 // The entire received buffer.
67 ByteBuffer data;
68
69 // The bytes we have yet to flush. (This is a slice of `data`)
70 ReadonlyBytes pending_flush;
71 };
72
73 Vector<NonnullOwnPtr<ReceivedBuffer>> m_received_buffers;
74
75 size_t m_buffered_size { 0 };
76 size_t m_received_size { 0 };
77 Optional<u32> m_content_length;
78 Optional<ssize_t> m_current_chunk_remaining_size;
79 Optional<size_t> m_current_chunk_total_size;
80 bool m_can_stream_response { true };
81 bool m_should_read_chunk_ending_line { false };
82 bool m_has_scheduled_finish { false };
83};
84
85}