Line data Source code
1 : #ifndef THINGER_HTTP_SERVER_UPGRADE_HPP
2 : #define THINGER_HTTP_SERVER_UPGRADE_HPP
3 :
4 : // What a connection upgraded or taken over from the server is handed with (see
5 : // response::upgrade_websocket(), upgrade_websocket_stream(), start_sse() and take_over()), and
6 : // the options of those upgrades. Light: only declarations of the connection types, so that
7 : // response.hpp does not bring them in.
8 :
9 : #include <chrono>
10 : #include <cstddef>
11 : #include <cstdint>
12 : #include <functional>
13 : #include <memory>
14 : #include <optional>
15 : #include <string>
16 : #include <vector>
17 : #include "../../util/types.hpp"
18 :
19 : namespace thinger::asio {
20 : class socket;
21 : class websocket;
22 : }
23 :
24 : namespace thinger::http {
25 :
26 : // What a connection of a server serves (see connection_tracker.hpp)
27 : enum class connection_type : uint8_t;
28 :
29 : class websocket_connection;
30 : class sse_connection;
31 :
32 : namespace detail {
33 : // The server's tracking of a connection taken over (connection_tracker.hpp), not public
34 : class taken_over_tracking;
35 : }
36 :
37 : /**
38 : * The link between a connection taken over (or upgraded) and the server it came from: its
39 : * statistics and its shutdown. A handle: copies share it. It does not keep the server alive;
40 : * with no server (a socket that does not come from one, a request dispatched in memory, a
41 : * default-constructed scope), or once the server is gone, its methods do nothing.
42 : *
43 : * The server counts the connection while the socket handed out (or a WebSocket built on it)
44 : * lives, or until closed() is called; whatever is still open at the end of a shutdown's grace
45 : * period is closed. On the thread of the socket.
46 : */
47 : class server_scope {
48 : public:
49 189 : server_scope() = default;
50 :
51 : // What the connection serves now, in the server statistics
52 : void set_type(connection_type type) const;
53 :
54 : // Be told when the server shuts down gracefully: `callback` is called once, on the
55 : // io_context of the socket, when the drain starts, so the owner can finish and close the
56 : // connection (e.g. with a WebSocket close 1001 Going Away). Set after the drain started, it
57 : // is still called, posted. Released before it is called: it may own the socket. What it
58 : // throws is logged
59 : void on_shutdown(sync_callback<void()> callback) const;
60 :
61 : // The new owner closed the connection: it no longer counts, and is not told of a shutdown.
62 : // Once; calling it again does nothing
63 : void closed() const;
64 :
65 : private:
66 : friend class detail::taken_over_tracking;
67 4306 : explicit server_scope(std::weak_ptr<detail::taken_over_tracking> tracking)
68 4306 : : tracking_(std::move(tracking)) {}
69 :
70 : std::weak_ptr<detail::taken_over_tracking> tracking_;
71 : };
72 :
73 : // A connection taken over from the server (see response::take_over()): its socket, any bytes
74 : // the server had already read past the request that took it over, and its scope
75 : struct upgraded_connection {
76 : std::shared_ptr<asio::socket> socket;
77 : std::string buffered;
78 : server_scope scope;
79 : };
80 :
81 : using takeover_handler = sync_callback<void(upgraded_connection)>;
82 : // The same, as a coroutine (run on the io_context of the socket)
83 : using takeover_coroutine = std::function<awaitable<void>(upgraded_connection)>;
84 :
85 : // Options of a WebSocket upgrade, with a message interface (response::upgrade_websocket()) or
86 : // as a byte stream (response::upgrade_websocket_stream())
87 : struct websocket_accept_options {
88 : // Subprotocols the handler speaks, alternatives included (e.g. "mqtt", "mqttv3.1",
89 : // "mqttv3.1.1"). The first one the client offers (Sec-WebSocket-Protocol, in its order of
90 : // preference) that is in this list is accepted. With the message interface, a client
91 : // offering subprotocols none of which is here is rejected with 400 (also with an empty
92 : // list); as a byte stream, it is accepted without one, unless protocol_required
93 : std::vector<std::string> protocols;
94 : // With protocols: a client offering none of them is rejected with 400. Otherwise it is
95 : // accepted without a subprotocol (and the handler gets an empty one)
96 : bool protocol_required = true;
97 : // As a byte stream: messages written binary, or text (the message interface writes each
98 : // message as it is sent)
99 : bool binary = true;
100 : // With the message interface: the largest message received (at least 1 byte); a larger one
101 : // closes with 1009 (Message Too Big). A byte stream has no messages, nor this limit
102 : size_t max_message_size = size_t{16} * 1024 * 1024;
103 : // Ping the client once nothing was received from it for this long, and close the connection
104 : // once nothing was received for idle_timeout (pongs included); 0 turns each off. Unset, the
105 : // default of the upgrade: 60 s and 120 s with the message interface, off as a byte stream
106 : std::optional<std::chrono::milliseconds> ping_interval;
107 : std::optional<std::chrono::milliseconds> idle_timeout;
108 : };
109 :
110 : // A WebSocket upgraded as a byte stream (see response::upgrade_websocket_stream()): the
111 : // WebSocket (holding any frames the client sent right after its request), the subprotocol
112 : // negotiated (empty if none), and its scope
113 : struct upgraded_websocket {
114 : std::shared_ptr<asio::websocket> stream;
115 : std::string protocol;
116 : server_scope scope;
117 : };
118 :
119 : using websocket_stream_handler = sync_callback<void(upgraded_websocket)>;
120 : using websocket_stream_coroutine = std::function<awaitable<void>(upgraded_websocket)>;
121 :
122 : // A WebSocket with a message interface, and an event stream
123 : using websocket_handler = sync_callback<void(std::shared_ptr<websocket_connection>)>;
124 : using websocket_coroutine = std::function<awaitable<void>(std::shared_ptr<websocket_connection>)>;
125 : using sse_handler = sync_callback<void(std::shared_ptr<sse_connection>)>;
126 : using sse_coroutine = std::function<awaitable<void>(std::shared_ptr<sse_connection>)>;
127 :
128 : // Options of an event stream (response::start_sse())
129 : struct sse_options {
130 : // Interval of the keep-alive comments written while nothing else is (0: none); see
131 : // sse_connection::set_keepalive()
132 513 : std::chrono::milliseconds keepalive{15000};
133 : };
134 :
135 : }
136 :
137 : #endif
|