userver: userver/server/request/request_context.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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
13USERVER_NAMESPACE_BEGIN
14
15namespace server::request {
16
17namespace impl {
18class InternalRequestContext;
19}
20
21/// @brief Stores request-specific data during request processing.
22///
23/// For example: you can store some data in `HandleRequestThrow()` method
24/// and access this data in `GetResponseDataForLogging()` method.
25class RequestContext final {
26 public:
27 RequestContext();
28
29 RequestContext(RequestContext&&) noexcept;
30
31 RequestContext(const RequestContext&) = delete;
32
33 ~RequestContext();
34
35 /// @brief Stores user data if it was not previously stored in this.
36 /// @throw std::runtime_error if user data was already stored.
37 template <typename Data>
38 Data& SetUserData(Data data);
39
40 /// @brief Emplaces user data if it was not previously stored in this.
41 /// @throw std::runtime_error if user data was already stored.
42 template <typename Data, typename... Args>
43 Data& EmplaceUserData(Args&&... args);
44
45 /// @returns Stored user data
46 /// @throws std::runtime_error if no data was stored
47 /// @throws std::bad_any_cast if data of different type was stored
48 template <typename Data>
49 Data& GetUserData();
50
51 /// @returns Stored user data
52 /// @throws std::runtime_error if no data was stored
53 /// @throws std::bad_any_cast if data of different type was stored
54 template <typename Data>
55 const Data& GetUserData() const;
56
57 /// @returns A pointer to data of type Data if it was stored before during
58 /// current request processing or nullptr otherwise
59 template <typename Data>
61
62 /// @returns A pointer to data of type Data if it was stored before during
63 /// current request processing or nullptr otherwise
64 template <typename Data>
66
67 /// @brief Erases the user data.
68 void EraseUserData();
69
70 /// @brief Stores the data with specified name if it was not previously stored
71 /// in this.
72 /// @throw std::runtime_error if data with such name was already stored.
73 template <typename Data>
74 Data& SetData(std::string name, Data data);
75
76 /// @brief Emplaces the data with specified name if it was not previously
77 /// stored in this.
78 /// @throw std::runtime_error if data with such name was already stored.
79 template <typename Data, typename... Args>
80 Data& EmplaceData(std::string name, Args&&... args);
81
82 /// @returns Stored data with specified name.
83 /// @throws std::runtime_error if no data was stored
84 /// @throws std::bad_any_cast if data of different type was stored
85 template <typename Data>
86 Data& GetData(std::string_view name);
87
88 /// @returns Stored data with specified name.
89 /// @throws std::runtime_error if no data was stored
90 /// @throws std::bad_any_cast if data of different type was stored
91 template <typename Data>
92 const Data& GetData(std::string_view name) const;
93
94 /// @returns Stored data with specified name or nullptr if no data found.
95 /// @throws std::bad_any_cast if data of different type was stored.
96 template <typename Data>
98
99 /// @returns Stored data with specified name or nullptr if no data found.
100 /// @throws std::bad_any_cast if data of different type was stored.
101 template <typename Data>
103 std::string_view name) const;
104
105 /// @brief Erase data with specified name.
106 void EraseData(std::string_view name);
107
108 // TODO : TAXICOMMON-8252
109 impl::InternalRequestContext& GetInternalContext();
110
111 private:
112 utils::AnyMovable& SetUserAnyData(utils::AnyMovable&& data);
113 utils::AnyMovable& GetUserAnyData();
114 utils::AnyMovable* GetUserAnyDataOptional();
115 void EraseUserAnyData();
116
117 utils::AnyMovable& SetAnyData(std::string&& name, utils::AnyMovable&& data);
118 utils::AnyMovable& GetAnyData(std::string_view name);
119 utils::AnyMovable* GetAnyDataOptional(std::string_view name);
120 void EraseAnyData(std::string_view name);
121
122 class Impl;
123 static constexpr std::size_t kPimplSize = 112;
124 utils::FastPimpl<Impl, kPimplSize, alignof(void*)> impl_;
125};
126
127template <typename Data>
128Data& RequestContext::SetUserData(Data data) {
129 static_assert(!std::is_const_v<Data>,
130 "Data stored in RequestContext is mutable if RequestContext is "
131 "not `const`. Remove the `const` from the template parameter "
132 "of SetUserData as it makes no sense");
133 static_assert(
134 !std::is_reference_v<Data>,
135 "Data in RequestContext is stored by copy. Remove the reference "
136 "from the template parameter of SetUserData as it makes no sense");
137 return utils::AnyCast<Data&>(SetUserAnyData(std::move(data)));
138}
139
140template <typename Data, typename... Args>
141Data& RequestContext::EmplaceUserData(Args&&... args) {
142 // NOLINTNEXTLINE(google-readability-casting)
143 auto& data = SetUserAnyData(Data(std::forward<Args>(args)...));
144 return utils::AnyCast<Data&>(data);
145}
146
147template <typename Data>
148Data& RequestContext::GetUserData() {
149 return utils::AnyCast<Data&>(GetUserAnyData());
150}
151
152template <typename Data>
153const Data& RequestContext::GetUserData() const {
154 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
155 return const_cast<RequestContext*>(this)->GetUserData<Data>();
156}
157
158template <typename Data>
160 auto* data = GetUserAnyDataOptional();
161 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
162}
163
164template <typename Data>
166 const {
167 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
168 return const_cast<RequestContext*>(this)->GetUserDataOptional<Data>();
169}
170
171inline void RequestContext::EraseUserData() { EraseUserAnyData(); }
172
173template <typename Data>
174Data& RequestContext::SetData(std::string name, Data data) {
175 static_assert(!std::is_const_v<Data>,
176 "Data stored in RequestContext is mutable if RequestContext is "
177 "not `const`. Remove the `const` from the template parameter "
178 "of SetData as it makes no sense");
179 static_assert(
180 !std::is_reference_v<Data>,
181 "Data in RequestContext is stored by copy. Remove the reference "
182 "from the template parameter of SetData as it makes no sense");
183 return utils::AnyCast<Data&>(SetAnyData(std::move(name), std::move(data)));
184}
185
186template <typename Data, typename... Args>
187Data& RequestContext::EmplaceData(std::string name, Args&&... args) {
188 // NOLINTNEXTLINE(google-readability-casting)
189 auto& data = SetAnyData(std::move(name), Data(std::forward<Args>(args)...));
190 return utils::AnyCast<Data&>(data);
191}
192
193template <typename Data>
194Data& RequestContext::GetData(std::string_view name) {
195 return utils::AnyCast<Data&>(GetAnyData(name));
196}
197
198template <typename Data>
199const Data& RequestContext::GetData(std::string_view name) const {
200 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
201 return const_cast<RequestContext*>(this)->GetData<Data>(name);
202}
203
204template <typename Data>
207 auto* data = GetAnyDataOptional(name);
208 return data ? &utils::AnyCast<Data&>(*data) : nullptr;
209}
210
211template <typename Data>
213 std::string_view name) const {
214 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
215 return const_cast<RequestContext*>(this)->GetDataOptional<Data>(name);
216}
217
218inline void RequestContext::EraseData(std::string_view name) {
219 EraseAnyData(name);
220}
221
222} // namespace server::request
223
224USERVER_NAMESPACE_END