userver: userver/server/http/http_request.hpp Source File
Loading...
Searching...
No Matches
http_request.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/http/http_request.hpp
4/// @brief @copybrief server::http::HttpRequest
5
6#include <chrono>
7#include <string>
8#include <type_traits>
9#include <vector>
10
11#include <userver/engine/task/task_processor_fwd.hpp>
12
13#include <userver/engine/io/sockaddr.hpp>
14#include <userver/http/url.hpp>
15#include <userver/server/http/form_data_arg.hpp>
16#include <userver/server/http/http_method.hpp>
17#include <userver/server/http/http_response.hpp>
18#include <userver/utils/datetime/wall_coarse_clock.hpp>
19#include <userver/utils/impl/internal_tag.hpp>
20#include <userver/utils/impl/transparent_hash.hpp>
21#include <userver/utils/str_icase.hpp>
22
23USERVER_NAMESPACE_BEGIN
24
25namespace server::handlers {
26class HttpHandlerBase;
27} // namespace server::handlers
28
29namespace engine::io {
30class RwBase;
31}
32
33/// Server parts of the HTTP protocol implementation.
34namespace server::http {
35
36namespace impl {
37class Http2StreamEventProducer;
38}
39
40/// @brief HTTP Request data.
41/// @note do not create HttpRequest by hand in tests,
42/// use HttpRequestBuilder instead.
43class HttpRequest final {
44public:
45 using HeadersMap = USERVER_NAMESPACE::http::headers::HeaderMap;
46
47 using HeadersMapKeys = decltype(utils::impl::MakeKeysView(HeadersMap()));
48
49 using CookiesMap = std::unordered_map<std::string, std::string, utils::StrCaseHash>;
50
51 using CookiesMapKeys = decltype(utils::impl::MakeKeysView(CookiesMap()));
52
53 /// @cond
54 explicit HttpRequest(request::ResponseDataAccounter& data_accounter, utils::impl::InternalTag);
55 /// @endcond
56
57 HttpRequest(HttpRequest&&) = delete;
58 HttpRequest(const HttpRequest&) = delete;
59
60 ~HttpRequest();
61
62 /// @return HTTP method (e.g. GET/POST)
63 const HttpMethod& GetMethod() const;
64
65 /// @return HTTP method as a string (e.g. "GET")
66 const std::string& GetMethodStr() const;
67
68 /// @return Major version of HTTP. For example, for HTTP 1.0 it returns 1
69 int GetHttpMajor() const;
70
71 /// @return Minor version of HTTP. For example, for HTTP 1.0 it returns 0
72 int GetHttpMinor() const;
73
74 /// @brief Get HTTP request target as provided by the client (see
75 /// https://www.rfc-editor.org/rfc/rfc7230#section-5.3). May contain the whole URL, but usually it consists of path
76 /// and query string.
77 const std::string& GetUrl() const;
78
79 /// @brief Get the path part of HTTP request URL.
80 ///
81 /// Unlike @ref server::handlers::HandlerConfig::path, path parameters are not replaced with placeholders, this is
82 /// the original highly cardinal path.
83 const std::string& GetRequestPath() const;
84
85 /// @cond
86 std::chrono::duration<double> GetResponseTime() const;
87 /// @endcond
88
89 /// @return Host from the URL.
90 const std::string& GetHost() const;
91
92 /// @return Request remote (peer's) address
93 const engine::io::Sockaddr& GetRemoteAddress() const;
94
95 /// @return First argument value with name `arg_name` or an empty string if no
96 /// such argument.
97 /// Arguments are extracted from:
98 /// - query part of the URL,
99 /// - the HTTP body (only if `parse_args_from_body: true` for handler is set).
100 ///
101 /// In both cases, arg keys and values are url-decoded automatically when
102 /// parsing into the HttpRequest.
103 const std::string& GetArg(std::string_view arg_name) const;
104
105 /// @return Argument values with name `arg_name` or an empty vector if no
106 /// such argument.
107 /// Arguments are extracted from:
108 /// - query part of the URL,
109 /// - the HTTP body (only if `parse_args_from_body: true` for handler is set).
110 ///
111 /// In both cases, arg keys and values are url-decoded automatically when
112 /// parsing into the HttpRequest.
113 const std::vector<std::string>& GetArgVector(std::string_view arg_name) const;
114
115 /// @return true if argument with name arg_name exists, false otherwise.
116 /// Arguments are extracted from:
117 /// - query part of the URL,
118 /// - the HTTP body (only if `parse_args_from_body: true` for handler is set).
119 ///
120 /// In both cases, arg keys and values are url-decoded automatically when
121 /// parsing into the HttpRequest.
122 bool HasArg(std::string_view arg_name) const;
123
124 /// @return Count of arguments.
125 /// Arguments are extracted from:
126 /// - query part of the URL,
127 /// - the HTTP body (only if `parse_args_from_body: true` for handler is set).
128 size_t ArgCount() const;
129
130 /// @return List of names of arguments.
131 /// Arguments are extracted from:
132 /// - query part of the URL,
133 /// - the HTTP body (only if `parse_args_from_body: true` for handler is set).
134 std::vector<std::string> ArgNames() const;
135
136 /// @brief Reconstruct the request URL with selected query args masked.
137 ///
138 /// Iterates all query arguments, replacing each value with `"***"` when
139 /// `is_masked_arg_name(name)` returns true.
140 template <typename Predicate>
141 requires std::is_invocable_r_v<bool, Predicate, std::string_view>
142 std::string GetMaskedUrl(Predicate is_masked_arg_name) const {
143 const auto names = ArgNames();
144 std::vector<std::pair<std::string_view, std::string_view>> args;
145
146 // Common case: each arg vector size is 1, so hope we don't need more
147 args.reserve(names.size());
148
149 for (const auto& name : names) {
150 for (const auto& value : GetArgVector(name)) {
151 args.emplace_back(name, is_masked_arg_name(name) ? "***" : std::string_view{value});
152 }
153 }
154 return USERVER_NAMESPACE::http::MakeUrl(GetRequestPath(), args);
155 }
156
157 /// @return First argument value with name arg_name from multipart/form-data
158 /// request or an empty FormDataArg if no such argument.
159 const FormDataArg& GetFormDataArg(std::string_view arg_name) const;
160
161 /// @return Argument values with name arg_name from multipart/form-data
162 /// request or an empty FormDataArg if no such argument.
163 const std::vector<FormDataArg>& GetFormDataArgVector(std::string_view arg_name) const;
164
165 /// @return true if argument with name arg_name exists in multipart/form-data
166 /// request, false otherwise.
167 bool HasFormDataArg(std::string_view arg_name) const;
168
169 /// @return Count of multipart/form-data arguments.
170 size_t FormDataArgCount() const;
171
172 /// @return List of names of multipart/form-data arguments.
173 std::vector<std::string> FormDataArgNames() const;
174
175 /// @return Named argument from URL path with wildcards.
176 /// @note Path args are currently NOT url-decoded automatically.
177 const std::string& GetPathArg(std::string_view arg_name) const;
178
179 /// @return Argument from URL path with wildcards by its 0-based index.
180 /// @note Path args are currently NOT url-decoded automatically.
181 const std::string& GetPathArg(size_t index) const;
182
183 /// @return true if named argument from URL path with wildcards exists, false
184 /// otherwise.
185 bool HasPathArg(std::string_view arg_name) const;
186
187 /// @return true if argument with index from URL path with wildcards exists,
188 /// false otherwise.
189 bool HasPathArg(size_t index) const;
190
191 /// @return Number of wildcard arguments in URL path.
192 size_t PathArgCount() const;
193
194 /// @return Value of the header with case insensitive name header_name, or an
195 /// empty string if no such header.
196 const std::string& GetHeader(std::string_view header_name) const;
197
198 /// @overload
199 const std::string& GetHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader& header_name) const;
200
201 /// @return true if header with case insensitive name header_name exists,
202 /// false otherwise.
203 bool HasHeader(std::string_view header_name) const;
204
205 /// @overload
206 bool HasHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader& header_name) const;
207
208 /// @return Number of headers.
209 size_t HeaderCount() const;
210
211 /// Removes the header with case insensitive name header_name.
212 void RemoveHeader(std::string_view header_name);
213
214 /// @overload
215 void RemoveHeader(const USERVER_NAMESPACE::http::headers::PredefinedHeader& header_name);
216
217 /// @return List of headers names.
218 HeadersMapKeys GetHeaderNames() const;
219
220 /// @return HTTP headers.
221 const HeadersMap& GetHeaders() const;
222
223 /// @return Value of the cookie with case sensitive name cookie_name, or an
224 /// empty string if no such cookie exists.
225 const std::string& GetCookie(const std::string& cookie_name) const;
226
227 /// @return true if cookie with case sensitive name cookie_name exists, false
228 /// otherwise.
229 bool HasCookie(const std::string& cookie_name) const;
230
231 /// @return Number of cookies.
232 size_t CookieCount() const;
233
234 /// @return List of cookies names.
235 CookiesMapKeys GetCookieNames() const;
236
237 /// @return HTTP cookies.
238 const CookiesMap& RequestCookies() const;
239
240 /// @return HTTP body.
241 const std::string& RequestBody() const;
242
243 /// @return moved out HTTP body. `this` is modified.
244 std::string ExtractRequestBody();
245
246 /// @cond
247 void SetRequestBody(std::string body);
248 void ParseArgsFromBody();
249 bool IsFinal() const noexcept;
250 /// @endcond
251
252 /// @brief Set the response status code.
253 ///
254 /// Equivalent to this->GetHttpResponse().SetStatus(status).
255 void SetResponseStatus(HttpStatus status) const;
256
257 /// @return true if the body of the request is still compressed. In other
258 /// words returns true if the static option `decompress_request` of a handler
259 /// was set to `false` and this is a compressed request.
260 bool IsBodyCompressed() const;
261
262 HttpResponse& GetHttpResponse() const noexcept;
263
264 /// Get approximate time point of request handling start
265 std::chrono::steady_clock::time_point GetStartTime() const;
266
267 /// @cond
268 void MarkAsInternalServerError() const;
269
270 void WriteAccessLogs(
271 const logging::TextLoggerPtr& logger_access,
272 const logging::TextLoggerPtr& logger_access_tskv,
273 const std::string& remote_address
274 ) const;
275
276 void WriteAccessLog(
277 const logging::TextLoggerPtr& logger_access,
278 utils::datetime::WallCoarseClock::time_point tp,
279 const std::string& remote_address
280 ) const;
281
282 void WriteAccessTskvLog(
283 const logging::TextLoggerPtr& logger_access_tskv,
284 utils::datetime::WallCoarseClock::time_point tp,
285 const std::string& remote_address
286 ) const;
287
288 using UpgradeCallback = std::function<void(std::unique_ptr<engine::io::RwBase>&&, engine::io::Sockaddr&&)>;
289
290 bool IsUpgradeWebsocket() const;
291 void SetUpgradeWebsocket(UpgradeCallback cb) const;
292 void DoUpgrade(std::unique_ptr<engine::io::RwBase>&& socket, engine::io::Sockaddr&& peer_name) const;
293 /// @endcond
294
295private:
296 void SetPathArgs(std::vector<std::pair<std::string, std::string>> args);
297
298 void SetHttpHandler(const handlers::HttpHandlerBase& handler);
299 const handlers::HttpHandlerBase* GetHttpHandler() const;
300
301 void SetTaskProcessor(engine::TaskProcessor& task_processor);
302 engine::TaskProcessor* GetTaskProcessor() const;
303
304 // HTTP/2.0 only
305 void SetResponseStreamId(std::int32_t);
306 void SetStreamProducer(impl::Http2StreamEventProducer&& producer);
307
308 friend class HttpRequestBuilder;
309 friend class HttpRequestHandler;
310
311 struct Impl;
312 utils::FastPimpl<Impl, 1936, 16> pimpl_;
313};
314
315} // namespace server::http
316
317USERVER_NAMESPACE_END