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