Line data Source code
1 : #ifndef API_REQUEST_HPP
2 : #define API_REQUEST_HPP
3 :
4 : #include <cstdint>
5 : #include <string>
6 : #include <memory>
7 : #include <optional>
8 : #include <set>
9 : #include <vector>
10 : #include <nlohmann/json.hpp>
11 : #include <boost/algorithm/string.hpp>
12 :
13 : #include "http_stream.hpp"
14 : #include "body_reader.hpp"
15 : #include "body_decoders.hpp"
16 : #include "multipart.hpp"
17 : #include "request_context.hpp"
18 : #include "../common/http_request.hpp"
19 : #include "../common/http_response.hpp"
20 : #include "../../util/types.hpp"
21 :
22 : namespace thinger::http{
23 :
24 : // Maximum request body size unless the application or the route set theirs
25 : inline constexpr std::uint64_t default_max_body_size = 8 * 1024 * 1024;
26 :
27 : // Why the scope of a request was cancelled (see request::cancelled()):
28 : // - client_gone: its client reset the connection, or a read or write on it failed, or it
29 : // ended before the request was complete (a client that only closes its sending side
30 : // after a complete request still gets its response: that is not client_gone);
31 : // - timeout: the timeout of its route (or of its in-memory dispatch) expired;
32 : // - shutdown: the server reached the deadline of its shutdown with the request in progress.
33 : // The library interrupts a handler for a reason only if its route declared it (see
34 : // route::cancel_on), and always for shutdown
35 : enum class cancel_reason : uint8_t { none, client_gone, timeout, shutdown };
36 :
37 : // Forward declarations
38 : class route;
39 : class virtual_host;
40 : class trusted_proxies;
41 : struct body_settings;
42 : class http_application;
43 : namespace proxy_detail { class proxy_exchange; }
44 :
45 : /**
46 : * Class that represents a single HTTP request over the API. It means, that the HTTP request
47 : * was matched to some of the registered endpoints in the API. It holds where its body is
48 : * read from (its connection, or memory), the stream associated to the HTTP request, and the
49 : * HTTP request itself.
50 : */
51 : class request{
52 : public:
53 : /// A request whose body comes from `source` (none: no body beyond what it was given,
54 : /// and no connection), answered on `stream` (none in memory)
55 : request(std::unique_ptr<detail::request_source> source,
56 : std::shared_ptr<http_stream> http_stream,
57 : std::shared_ptr<http_request> http_request);
58 :
59 : virtual ~request();
60 :
61 : // Not copyable: its body reader refers to it
62 : request(const request&) = delete;
63 : request& operator=(const request&) = delete;
64 :
65 : public:
66 : /// get parameter
67 : const std::string& operator[](const std::string& param) const;
68 :
69 : /// has parameter
70 : bool has(const std::string& param) const;
71 :
72 : /// erase parameter
73 : bool erase(const std::string& param);
74 :
75 : std::string debug_parameters() const;
76 :
77 : std::shared_ptr<http_request> get_http_request();
78 : std::shared_ptr<const http_request> get_http_request() const;
79 :
80 : /// Client IP: the peer address or, if the peer is a trusted proxy (see
81 : /// http_application::set_trusted_proxies), the client address it forwarded
82 : std::string get_request_ip() const;
83 :
84 : /// Address of the direct peer (the connection's remote IP), whatever it forwards
85 : std::string get_peer_ip() const;
86 :
87 : /// The connection the request came from: its peer and local addresses, and whether it
88 : /// is TLS (for requests dispatched in memory, the peer address of the dispatch). Empty
89 : /// once the connection is gone
90 : connection_info connection() const;
91 :
92 : /// TLS session of the connection (e.g. the client certificate on an mTLS route): none
93 : /// without TLS, in memory, or once the connection is gone
94 : std::optional<asio::tls_session> tls() const;
95 :
96 : /// Whether the request came on a TLS connection whose handshake (SNI) chose another
97 : /// client certificate mode or certificate than its host name (Host) gets: it must not be
98 : /// served there (421, see asio::tls_handshake_record::misdirected()). False at once without
99 : /// TLS, in memory, or once the connection is gone
100 : bool misdirected() const;
101 :
102 : /// Client scheme, "http" or "https": the one of the connection (TLS or not; for
103 : /// requests dispatched in memory, the one of the request, see http_request::is_ssl())
104 : /// or, if the peer is a trusted proxy (see http_application::set_trusted_proxies),
105 : /// the one it forwarded for the client of get_request_ip(): the X-Forwarded-Proto value
106 : /// aligned with X-Forwarded-For (or its last one), or the proto of the Forwarded element
107 : /// giving the client address (see trusted_proxies::resolve())
108 : std::string get_request_scheme() const;
109 :
110 : /// Peer address of requests without a connection (in-memory dispatch)
111 1176 : void set_peer_ip(std::string ip) { peer_ip_ = std::move(ip); }
112 :
113 : /// Proxies whose forwarding header get_request_ip() accepts (set by the server)
114 27559 : void set_trusted_proxies(std::shared_ptr<const trusted_proxies> proxies) { trusted_proxies_ = std::move(proxies); }
115 :
116 : /// Trusted proxies set by the server (null if none is trusted)
117 675 : const std::shared_ptr<const trusted_proxies>& get_trusted_proxies() const { return trusted_proxies_; }
118 :
119 : /// Virtual host serving the request (the application itself for the default host)
120 477 : const virtual_host* get_virtual_host() const { return virtual_host_; }
121 27136 : void set_virtual_host(const virtual_host* host) { virtual_host_ = host; }
122 :
123 : /// Captures of the host pattern that matched: [0] is the host name and [1..] the
124 : /// groups, e.g. the subdomain matched by "*" in "*.example.com" (the labels named
125 : /// with ":name" are also request parameters). Empty for exact and default hosts.
126 9 : const std::vector<std::string>& get_host_matches() const { return host_matches_; }
127 27 : void set_host_matches(std::vector<std::string> matches) { host_matches_ = std::move(matches); }
128 :
129 : // Convenience methods for accessing request data
130 :
131 : /// Get query parameter by key
132 : std::string query(const std::string& key) const;
133 :
134 : /// Get query parameter by key with default value
135 : std::string query(const std::string& key, const std::string& default_value) const;
136 :
137 : /// Get request body as string
138 : std::string body() const;
139 :
140 : /// Get request body parsed as JSON
141 : nlohmann::json json() const;
142 :
143 : /// Get request header by key
144 : std::string header(const std::string& key) const;
145 :
146 : std::shared_ptr<http_stream> get_http_stream() const;
147 :
148 : void set_uri_parameter(const std::string& param, const std::string& value);
149 :
150 : void add_uri_parameter(const std::string& param, const std::string& value);
151 :
152 : const std::string& get_uri_parameter(const std::string& param) const;
153 :
154 : const std::multimap<std::string, std::string>& get_uri_parameters() const;
155 :
156 : void set_auth_groups(const std::set<std::string>& groups);
157 :
158 : const std::set<std::string>& get_auth_groups() const;
159 :
160 : void set_auth_user(const std::string& auth_user);
161 :
162 : const std::string& get_auth_user() const;
163 :
164 : /// Typed values of this request (see request_context), e.g. the principal an
165 : /// authentication middleware stores for the route handler. Empty at first (or with the
166 : /// values of dispatch_options::context), they are destroyed with the request.
167 4251 : request_context& context() noexcept { return context_; }
168 : const request_context& context() const noexcept { return context_; }
169 :
170 : void set_matched_route(const route* route);
171 :
172 : const route* get_matched_route() const;
173 :
174 : // Whether the client asked to keep the connection (its Connection header and HTTP
175 : // version), not whether the server keeps it after the response
176 : bool keep_alive() const;
177 :
178 : // --- Cancellation (see cancel_reason, route::cancel_on) ---
179 :
180 : /// Why the scope of the request was cancelled: none until then (or for a request
181 : /// without a stream). Its handler goes on unless its route declared the reason (or
182 : /// the server shuts down): it looks here where it chooses
183 : cancel_reason cancelled() const;
184 :
185 : /// Completes once the scope of the request is cancelled, whatever the reason, and
186 : /// returns it; none if this wait is cancelled itself (e.g. by `||`). For a request
187 : /// without a stream it never completes. Await it on the executor of the handler
188 : thinger::awaitable<cancel_reason> client_gone();
189 :
190 : /// Slot cancelled (terminal) with the scope of the request while the handler runs,
191 : /// for the awaits the handler chooses to abandon then: bind it with
192 : /// boost::asio::bind_cancellation_slot, to one pending await at a time (asio's rule).
193 : /// Not connected for a request without a stream
194 : boost::asio::cancellation_slot cancellation_slot();
195 :
196 : // --- Body reading (see body_reader) ---
197 :
198 : /// Store read-ahead data: the bytes read past the request head (called by the
199 : /// connection before dispatch)
200 : void set_read_ahead(const uint8_t* data, size_t size);
201 :
202 : /// Read exactly `size` bytes (read-ahead first, then the source). TCP backpressure.
203 : /// Returns less at the end of the body, or if it fails (see get_body_error()), e.g.
204 : /// for a body over the maximum body size (a Content-Length one before reading it).
205 : thinger::awaitable<size_t> read(uint8_t* buffer, size_t size);
206 :
207 : /// Read up to `max_size` bytes (read-ahead first, then the source); 0 at the end of the
208 : /// body, or if it fails (see get_body_error()), as read(). A read cancelled (e.g. by
209 : /// `read_some() || timer`) returns 0 too, without failing: the body is still pending.
210 : thinger::awaitable<size_t> read_some(uint8_t* buffer, size_t max_size);
211 :
212 : /// Absolute deadline for the reads of the body, pending and later ones (read(),
213 : /// read_some(), read_body(), those of a multipart_reader), as Go's
214 : /// http.ResponseController.SetReadDeadline: the handler sets and moves it as it reads,
215 : /// as often as it likes, on the thread rules of those reads ("60 s more for each 64 MiB
216 : /// received"), which cuts a client that goes silent or trickles without cutting a long
217 : /// upload. Bytes already received (the read-ahead) are still returned past it.
218 : /// It replaces the request timeout (connection_options::request_timeout, or the one of
219 : /// the route) for the rest of the body; time_point::max() removes it, leaving only the
220 : /// idle timeout, which a deadline further away than it does not extend. It bounds no
221 : /// write. As it passes, the pending read returns what it read, or 0, and
222 : /// get_body_error() is body_error::timeout, for good. Nothing is answered for the
223 : /// handler (408 if it answers nothing), and the connection closes after the response,
224 : /// as with any body left unread. Without a connection (in memory) it does nothing: a
225 : /// body in memory never waits.
226 : void set_read_deadline(std::chrono::steady_clock::time_point deadline);
227 :
228 : /// Read full body into http_request content (for non-deferred dispatch), decoding
229 : /// its Content-Encoding (gzip, deflate, or a list of them; see util::decode_content).
230 : /// Fails if the body exceeds the maximum body size (see get_max_body_size()), a
231 : /// Content-Length one without reading it.
232 : /// Only reads what is still pending: do not mix it with read()/read_some() on
233 : /// the same request, or the stored body will be incomplete (and fail to
234 : /// decompress if Content-Encoding is set).
235 : thinger::awaitable<bool> read_body();
236 :
237 : /// Read a multipart/form-data body (see multipart_form): its fields in memory and its
238 : /// files in temporary files, within the limits of the options and the maximum body
239 : /// size. Check the form for errors (400 malformed, 413 over a limit, 415 not a form).
240 : /// To stream the parts instead, read them with a multipart_reader.
241 : thinger::awaitable<multipart_form> read_multipart(multipart_options options = {});
242 :
243 : /// Read and drop an unread body so the connection can be reused.
244 : /// Returns false if the body exceeds `max_size` or the read fails.
245 : thinger::awaitable<bool> discard_body(std::uint64_t max_size);
246 :
247 : /// Whether part of the body is still unread by read(), read_some() or read_body().
248 : bool has_pending_body() const;
249 :
250 : /// Why reading the body failed (body_error::none if it did not): too large, invalid
251 : /// chunked framing, connection closed before its end, undecodable Content-Encoding, or
252 : /// past its read deadline (see set_read_deadline())
253 : body_error get_body_error() const;
254 :
255 : /// Content-Length convenience (0 for chunked requests)
256 : size_t content_length() const;
257 :
258 : /// Whether the request uses chunked transfer encoding
259 : bool is_chunked() const;
260 :
261 : /// Remove and return the unconsumed read-ahead bytes (data following this request)
262 : std::vector<uint8_t> take_read_ahead();
263 :
264 : /// Maximum body size of every read (read_body(), read(), read_some()), also once
265 : /// decompressed: the one of the matched route, or of the application (set by the server)
266 27898 : void set_max_body_size(std::uint64_t size) { body_reader_.set_limit(size); }
267 3 : std::uint64_t get_max_body_size() const { return body_reader_.limit(); }
268 :
269 : /// How the matched route decodes the body (set by the server; the defaults if not)
270 27559 : void set_body_settings(const body_settings* settings) { body_settings_ = settings; }
271 : const body_settings& get_body_settings() const;
272 :
273 : private:
274 :
275 : /// After reading the body: once read to its end, none of it is left on the connection
276 : /// (see http_stream::input_pending())
277 : void note_body_read();
278 :
279 : /**
280 : * A stream is a channel inside the HTTP connection. i.e, while receiving multiple requests
281 : * and responses are generated asynchronously, it is required to know which response
282 : * belong to a given query, and provide an ordered response (to support HTTP pipelining).
283 : * With HTTP2.0 it is possible to provide responses without pipelining.
284 : */
285 : std::shared_ptr<http_stream> http_stream_;
286 :
287 : /**
288 : * Where the body is read from, and what is known of the connection (see
289 : * detail::request_source). After the stream it refers to, so destroyed before it
290 : */
291 : std::unique_ptr<detail::request_source> source_;
292 :
293 : /**
294 : * This is the request that originated the API Request, and required to know the body, the
295 : * content type, etc.
296 : */
297 : std::shared_ptr<http_request> http_request_;
298 :
299 : /**
300 : * Vector for storing the matched parameters found in the URL, like username, device, etc.
301 : */
302 : std::multimap<std::string, std::string> params_;
303 :
304 : std::string auth_user_;
305 :
306 : std::string peer_ip_;
307 :
308 : std::shared_ptr<const trusted_proxies> trusted_proxies_;
309 :
310 : const virtual_host* virtual_host_ = nullptr;
311 :
312 : std::vector<std::string> host_matches_;
313 :
314 : std::set<std::string> groups_;
315 :
316 : /// Values stored by the middlewares (or the in-memory dispatch) for the handler
317 : request_context context_;
318 :
319 : const route* matched_route_ = nullptr;
320 :
321 : /// Body framing and reading: read-ahead bytes, then the connection
322 : body_reader body_reader_;
323 :
324 : /// Body decoders, accepted types and limits of the application (null: defaults)
325 : const body_settings* body_settings_ = nullptr;
326 :
327 : /// The sink of the response, the deadline of a route timeout and the proxy watching the
328 : /// client reach the connection through the source
329 : friend class connection_sink;
330 : friend class http_application;
331 : friend class proxy_detail::proxy_exchange;
332 :
333 : /// Body parsed as JSON by the matched route, for callbacks taking it
334 : friend class route;
335 : nlohmann::json json_body_;
336 :
337 : /// Type of the body the matched route accepted (matched before the body is read):
338 : /// its media type (null until matched) and decoder (null if none). They point to the
339 : /// decoder registry for the media types its decoders list, else to body_type_.
340 : const media_type* body_media_type_ = nullptr;
341 : const body_format* body_format_ = nullptr;
342 : std::optional<body_type_match> body_type_;
343 : };
344 :
345 : }
346 :
347 :
348 : #endif
|