Line data Source code
1 : #ifndef API_REQUEST_HPP
2 : #define API_REQUEST_HPP
3 :
4 : #include <string>
5 : #include <memory>
6 : #include <set>
7 : #include <vector>
8 : #include <nlohmann/json.hpp>
9 : #include <boost/algorithm/string.hpp>
10 :
11 : #include "http_stream.hpp"
12 : #include "server_connection.hpp"
13 : #include "../common/http_response.hpp"
14 : #include "../../util/types.hpp"
15 :
16 : namespace thinger::http{
17 :
18 : // Forward declarations
19 : class route;
20 : enum class auth_level;
21 :
22 : /**
23 : * Class that represents a single HTTP request over the API. It means, that the HTTP request
24 : * was matched to some of the registered endpoints in the API. It holds the original HTTP
25 : * connection, the stream associated to the HTTP request, and the HTTP request itself.
26 : */
27 : class request{
28 : public:
29 : request(const std::shared_ptr<server_connection>& http_connection,
30 : const std::shared_ptr<http_stream>& http_stream,
31 : std::shared_ptr<http_request> http_request);
32 :
33 : virtual ~request();
34 :
35 : public:
36 : /// get parameter
37 : const std::string& operator[](const std::string& param) const;
38 :
39 : /// has parameter
40 : bool has(const std::string& param) const;
41 :
42 : /// erase parameter
43 : bool erase(const std::string& param);
44 :
45 : std::string debug_parameters() const;
46 :
47 : std::shared_ptr<http_request> get_http_request();
48 :
49 : std::string get_request_ip() const;
50 :
51 : // Convenience methods for accessing request data
52 :
53 : /// Get query parameter by key
54 : std::string query(const std::string& key) const;
55 :
56 : /// Get query parameter by key with default value
57 : std::string query(const std::string& key, const std::string& default_value) const;
58 :
59 : /// Get request body as string
60 : std::string body() const;
61 :
62 : /// Get request body parsed as JSON
63 : nlohmann::json json() const;
64 :
65 : /// Get request header by key
66 : std::string header(const std::string& key) const;
67 :
68 : std::shared_ptr<server_connection> get_http_connection() const;
69 :
70 : std::shared_ptr<http_stream> get_http_stream() const;
71 :
72 : //void add_matched_param(const std::string& param);
73 :
74 : void set_uri_parameter(const std::string& param, const std::string& value);
75 :
76 : void add_uri_parameter(const std::string& param, const std::string& value);
77 :
78 : const std::string& get_uri_parameter(const std::string& param) const;
79 :
80 : const std::multimap<std::string, std::string>& get_uri_parameters() const;
81 :
82 : void set_auth_groups(const std::set<std::string>& groups);
83 :
84 : const std::set<std::string>& get_auth_groups() const;
85 :
86 : void set_auth_user(const std::string& auth_user);
87 :
88 : const std::string& get_auth_user() const;
89 :
90 : void set_matched_route(const route* route);
91 :
92 : const route* get_matched_route() const;
93 :
94 : auth_level get_required_auth_level() const;
95 :
96 :
97 : bool keep_alive() const;
98 :
99 : // --- Deferred body reading support ---
100 :
101 : /// Store read-ahead data (called by server_connection before dispatch)
102 : void set_read_ahead(const uint8_t* data, size_t size);
103 :
104 : /// Read exactly `size` bytes (read-ahead first, then socket). TCP backpressure.
105 : thinger::awaitable<size_t> read(uint8_t* buffer, size_t size);
106 :
107 : /// Read up to `max_size` bytes (read-ahead first, then socket).
108 : thinger::awaitable<size_t> read_some(uint8_t* buffer, size_t max_size);
109 :
110 : /// Read full body into http_request content (for non-deferred dispatch).
111 : thinger::awaitable<bool> read_body();
112 :
113 : /// Content-Length convenience (0 for chunked requests)
114 : size_t content_length() const;
115 :
116 : /// Whether the request uses chunked transfer encoding
117 : bool is_chunked() const;
118 :
119 : /// Bytes remaining in read-ahead buffer
120 : size_t read_ahead_available() const;
121 :
122 : /// Direct socket access (for pipe-style forwarding)
123 : std::shared_ptr<asio::socket> get_socket() const;
124 :
125 : //exec_result get_request_data() const;
126 :
127 : private:
128 :
129 : /**
130 : * HTTP connection is the wrapper for a raw socket, being able to parse request and to
131 : * pipeline HTTP responses
132 : */
133 : std::weak_ptr<server_connection> http_connection_;
134 :
135 : /**
136 : * A stream is a channel inside the HTTP connection. i.e, while receiving multiple requests
137 : * and responses are generated asynchronously, it is required to know which response
138 : * belong to a given query, and provide an ordered response (to support HTTP pipelining).
139 : * With HTTP2.0 it is possible to provide responses without pipelining.
140 : */
141 : std::weak_ptr<http_stream> http_stream_;
142 :
143 : /**
144 : * This is the request that originated the API Request, and required to know the body, the
145 : * content type, etc.
146 : */
147 : std::shared_ptr<http_request> http_request_;
148 :
149 : /**
150 : * Vector for storing the matched parameters found in the URL, like username, device, etc.
151 : */
152 : std::multimap<std::string, std::string> params_;
153 :
154 : std::string auth_user_;
155 :
156 : std::set<std::string> groups_;
157 :
158 : const route* matched_route_ = nullptr;
159 :
160 : /// Leftover data from header parsing buffer (for deferred body reading)
161 : std::vector<uint8_t> read_ahead_;
162 : size_t read_ahead_offset_ = 0;
163 :
164 : /// Raw read (bypasses chunked decoding) — reads from read-ahead, then socket
165 : thinger::awaitable<size_t> raw_read_some(uint8_t* buffer, size_t max_size);
166 :
167 : /// Chunked transfer encoding decoder state
168 : enum class chunk_state { size, size_lf, data, data_cr, data_lf, trailer_lf, done };
169 : chunk_state chunk_state_ = chunk_state::size;
170 : size_t chunk_remaining_ = 0;
171 : size_t chunk_size_accum_ = 0;
172 :
173 : /// Read with chunked decoding (transparent to caller)
174 : thinger::awaitable<size_t> read_some_chunked(uint8_t* buffer, size_t max_size);
175 :
176 : /// Max body size for non-deferred chunked read_body()
177 : size_t max_body_size_ = 8 * 1024 * 1024;
178 :
179 : public:
180 104 : void set_max_body_size(size_t size) { max_body_size_ = size; }
181 : };
182 :
183 : }
184 :
185 :
186 : #endif
|