userver: userver/server/request/request_context.hpp Source File
Loading...
Searching...
No Matches
request_context.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/request/request_context.hpp
4/// @brief @copybrief server::request::RequestContext
5
6#include <string>
7#include <string_view>
8#include <type_traits>
9
10#include <userver/utils/any_movable.hpp>
11#include <userver/utils/fast_pimpl.hpp>
12#include <userver/utils/statistics/labels.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace server::request {
17
18namespace impl {
19class InternalRequestContext;
20}
21
22/// @brief Stores request-specific data during request processing.
23///
24/// For example: you can store some data in `HandleRequestThrow()` method
25/// and access this data in `GetResponseDataForLogging()` method.
26class RequestContext final {
27public:
28 RequestContext();
29
30 RequestContext(RequestContext&&) noexcept;
31
32 RequestContext(const RequestContext&) = delete;
33
34 ~RequestContext();
35
36 /// @brief Stores user data if it was not previously stored in this.
37 /// @throw std::runtime_error if user data was already stored.
38 template <typename Data>
39 Data& SetUserData(Data data);
40
41 /// @brief Emplaces user data if it was not previously stored in this.
42 /// @throw std::runtime_error if user data was already stored.
43 template <typename Data, typename... Args>
44 Data& EmplaceUserData(Args&&... args);
45
46 /// @returns Stored user data
47 /// @throws std::runtime_error if no data was stored
48 /// @throws std::bad_any_cast if data of different type was stored
49 template <typename Data>
50 Data& GetUserData();
51
52 /// @returns Stored user data
53 /// @throws std::runtime_error if no data was stored
54 /// @throws std::bad_any_cast if data of different type was stored
55 template <typename Data>
56 const Data& GetUserData() const;
57
58 /// @returns A pointer to data of type Data if it was stored before during
59 /// current request processing or nullptr otherwise
60 template <typename Data>
61 std::remove_reference_t<Data>* GetUserDataOptional();
62
63 /// @returns A pointer to data of type Data if it was stored before during
64 /// current request processing or nullptr otherwise
65 template <typename Data>
66 const std::remove_reference_t<Data>* GetUserDataOptional() const;
67
68 /// @brief Erases the user data.
69 void EraseUserData();
70
71 /// @brief Stores the data with specified name if it was not previously stored
72 /// in this.
73 /// @throw std::runtime_error if data with such name was already stored.
74 template <typename Data>
75 Data& SetData(std::string name, Data data);
76
77 /// @brief Emplaces the data with specified name if it was not previously
78 /// stored in this.
79 /// @throw std::runtime_error if data with such name was already stored.
80 template <typename Data, typename... Args>
81 Data& EmplaceData(std::string name, Args&&... args);
82
83 /// @returns Stored data with specified name.
84 /// @throws std::runtime_error if no data was stored
85 /// @throws std::bad_any_cast if data of different type was stored
86 template <typename Data>
87 Data& GetData(std::string_view name);
88
89 /// @returns Stored data with specified name.
90 /// @throws std::runtime_error if no data was stored
91 /// @throws std::bad_any_cast if data of different type was stored
92 template <typename Data>
93 const Data& GetData(std::string_view name) const;
94
95 /// @returns Stored data with specified name or nullptr if no data found.
96 /// @throws std::bad_any_cast if data of different type was stored.
97 template <typename Data>
98 std::remove_reference_t<Data>* GetDataOptional(std::string_view name);
99
100 /// @returns Stored data with specified name or nullptr if no data found.
101 /// @throws std::bad_any_cast if data of different type was stored.
102 template <typename Data>
103 const std::remove_reference_t<Data>* GetDataOptional(std::string_view name) const;
104
105 /// @brief Erase data with specified name.
106 void EraseData(std::string_view name);
107
108 /// @brief Set the metrics shard (path + labels) for this request.
109 /// When set, handler metrics will be accumulated on a new subpath "http.handler.path.*"
110 /// and the provided labels would be set to each metric
111 /// @note If something (e.g. middleware) interrupts the request before this method is called
112 /// then the sharded metrics won't be written
113 void SetHandlerMetricsShard(std::string_view path, utils::statistics::LabelsSpan labels);
114
115 // TODO : TAXICOMMON-8252
116 impl::InternalRequestContext& GetInternalContext();
117
118private:
119 utils::AnyMovable& SetUserAnyData(utils::AnyMovable&& data);
120 utils::AnyMovable& GetUserAnyData();
121 utils::AnyMovable* GetUserAnyDataOptional();
122 void EraseUserAnyData();
123
124 utils::AnyMovable& SetAnyData(std::string&& name, utils::AnyMovable&& data);
125 utils::AnyMovable& GetAnyData(std::string_view name);
126 utils::AnyMovable* GetAnyDataOptional(std::string_view name);
127 void EraseAnyData(std::string_view name);
128
129 class Impl;
130 static constexpr std::size_t kPimplSize = 120;
131 utils::FastPimpl<Impl, kPimplSize, alignof(void*)> impl_;
132};
133
134template <typename Data>
135Data& RequestContext::SetUserData(Data data) {
136 static_assert(
137 !std::is_const_v<Data>,
138 "Data stored in RequestContext is mutable if RequestContext is "
139 "not `const`. Remove the `const` from the template parameter "
140 "of SetUserData as it makes no sense"
141 );
142 static_assert(
143 !std::is_reference_v<Data>,
144 "Data in RequestContext is stored by copy. Remove the reference "
145 "from the template parameter of SetUserData as it makes no sense"
146 );
147 return utils::AnyCast<Data&>(SetUserAnyData(std::move(data)));
148}
149
150template <typename Data, typename... Args>
151Data& RequestContext::EmplaceUserData(Args&&... args) {
152 // NOLINTNEXTLINE(google-readability-casting)
153 auto& data = SetUserAnyData(Data(std::forward<Args>(args)...));
154 return utils::AnyCast<Data&>(data);
155}
156
157template <typename Data>
158Data& RequestContext::GetUserData() {
159 return utils::AnyCast<Data&>(GetUserAnyData());
160}
161
162template <typename Data>
163const Data& RequestContext::GetUserData() const {
164 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
165 return const_cast<RequestContext*>(this)->GetUserData<Data>();
166}
167
168template <typename Data>
169std::remove_reference_t<Data>* RequestContext::GetUserDataOptional() {
170 auto* data = GetUserAnyDataOptional();
171 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
172}
173
174template <typename Data>
175const std::remove_reference_t<Data>* RequestContext::GetUserDataOptional() const {
176 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
177 return const_cast<RequestContext*>(this)->GetUserDataOptional<Data>();
178}
179
180inline void RequestContext::EraseUserData() { EraseUserAnyData(); }
181
182template <typename Data>
183Data& RequestContext::SetData(std::string name, Data data) {
184 static_assert(
185 !std::is_const_v<Data>,
186 "Data stored in RequestContext is mutable if RequestContext is "
187 "not `const`. Remove the `const` from the template parameter "
188 "of SetData as it makes no sense"
189 );
190 static_assert(
191 !std::is_reference_v<Data>,
192 "Data in RequestContext is stored by copy. Remove the reference "
193 "from the template parameter of SetData as it makes no sense"
194 );
195 return utils::AnyCast<Data&>(SetAnyData(std::move(name), std::move(data)));
196}
197
198template <typename Data, typename... Args>
199Data& RequestContext::EmplaceData(std::string name, Args&&... args) {
200 // NOLINTNEXTLINE(google-readability-casting)
201 auto& data = SetAnyData(std::move(name), Data(std::forward<Args>(args)...));
202 return utils::AnyCast<Data&>(data);
203}
204
205template <typename Data>
206Data& RequestContext::GetData(std::string_view name) {
207 return utils::AnyCast<Data&>(GetAnyData(name));
208}
209
210template <typename Data>
211const Data& RequestContext::GetData(std::string_view name) const {
212 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
213 return const_cast<RequestContext*>(this)->GetData<Data>(name);
214}
215
216template <typename Data>
217std::remove_reference_t<Data>* RequestContext::GetDataOptional(std::string_view name) {
218 auto* data = GetAnyDataOptional(name);
219 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
220}
221
222template <typename Data>
223const std::remove_reference_t<Data>* RequestContext::GetDataOptional(std::string_view name) const {
224 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
225 return const_cast<RequestContext*>(this)->GetDataOptional<Data>(name);
226}
227
228inline void RequestContext::EraseData(std::string_view name) { EraseAnyData(name); }
229
230} // namespace server::request
231
232USERVER_NAMESPACE_END