Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/beast2
8 : //
9 :
10 : #ifndef BOOST_BEAST2_SERVER_ROUTE_HANDLER_HPP
11 : #define BOOST_BEAST2_SERVER_ROUTE_HANDLER_HPP
12 :
13 : #include <boost/beast2/detail/config.hpp>
14 : #include <boost/beast2/detail/except.hpp>
15 : #include <boost/http_proto/request_parser.hpp> // VFALCO forward declare?
16 : #include <boost/http_proto/response.hpp> // VFALCO forward declare?
17 : #include <boost/http_proto/serializer.hpp> // VFALCO forward declare?
18 : #include <boost/url/url_view.hpp>
19 : #include <boost/url/segments_encoded_view.hpp>
20 : #include <boost/core/detail/string_view.hpp>
21 : #include <boost/system/error_code.hpp>
22 : #include <boost/assert.hpp>
23 :
24 : namespace boost {
25 : namespace beast2 {
26 :
27 : /** The type of value returned by route handlers
28 : */
29 : using route_result = system::error_code;
30 :
31 : /** Route handler return values
32 :
33 : These values determine how the caller proceeds after invoking
34 : a route handler. Each enumerator describes a distinct control
35 : action; whether the request was handled, should continue to the
36 : next route, transfers ownership of the session, or signals that
37 : the connection should be closed.
38 : */
39 : enum class route
40 : {
41 : /** The request was handled
42 :
43 : This indicates that the route handler processed
44 : the request and set up the response serializer.
45 : The calling function will write the response
46 : before reading the next request or closing
47 : the connection.
48 : */
49 : send,
50 :
51 : /** The route handler did not handle the request
52 :
53 : Indicates that the route handler declined to process
54 : the request. The caller will continue attempting to
55 : match subsequent route handlers until one returns
56 : `send` or no routes remain.
57 : */
58 : next,
59 :
60 : /** The route handler requests that the connection be closed
61 :
62 : Indicates that no further requests will be processed.
63 : The caller should close the connection once the current
64 : response, if any, has been sent.
65 : */
66 : close,
67 :
68 : /** The route handler is detaching from the session
69 :
70 : Indicates that ownership of the session or stream is
71 : being transferred to the handler. The caller will not
72 : perform further I/O or manage the connection after
73 : this return value.
74 : */
75 : detach,
76 :
77 : /** The route handler processed the request and sent the response
78 :
79 : Indicates that the handler has completed the response. The caller
80 : will read the next HTTP request if the connection is persistent,
81 : or close the connection otherwise.
82 : */
83 : done
84 : };
85 :
86 : } // beast2
87 : namespace system {
88 : template<>
89 : struct is_error_code_enum<
90 : ::boost::beast2::route>
91 : {
92 : static bool const value = true;
93 : };
94 : } // system
95 : namespace beast2 {
96 :
97 : namespace detail {
98 : struct BOOST_SYMBOL_VISIBLE route_cat_type
99 : : system::error_category
100 : {
101 : BOOST_BEAST2_DECL const char* name(
102 : ) const noexcept override;
103 : BOOST_BEAST2_DECL std::string message(
104 : int) const override;
105 : BOOST_BEAST2_DECL char const* message(
106 : int, char*, std::size_t
107 : ) const noexcept override;
108 0 : bool failed( int ) const noexcept override
109 0 : { return false; }
110 2 : BOOST_SYSTEM_CONSTEXPR route_cat_type()
111 2 : : error_category(0x51c90d393754ecdf )
112 : {
113 2 : }
114 : };
115 : BOOST_BEAST2_DECL extern route_cat_type route_cat;
116 : } // detail
117 :
118 : inline
119 : BOOST_SYSTEM_CONSTEXPR
120 : system::error_code
121 0 : make_error_code(route ev) noexcept
122 : {
123 : return system::error_code{static_cast<
124 : std::underlying_type<route>::type>(ev),
125 0 : detail::route_cat};
126 : }
127 :
128 : //------------------------------------------------
129 :
130 : class resumer;
131 :
132 : /** Function to detach a route handler from its session
133 :
134 : This holds an reference to an implementation
135 : which detaches the handler from its session.
136 : */
137 : class detacher
138 : {
139 : public:
140 : /** Base class of the implementation
141 : */
142 : struct owner
143 : {
144 : virtual resumer do_detach() = 0;
145 : virtual void do_resume(route_result const&) = 0;
146 : };
147 :
148 0 : detacher() = default;
149 : detacher(detacher const&) = default;
150 : detacher& operator=(detacher const&) = default;
151 :
152 : explicit
153 0 : detacher(
154 : owner& who) noexcept
155 0 : : p_(&who)
156 : {
157 0 : }
158 :
159 : /** Detach and invoke the given function
160 :
161 : The function will be invoked with this equivalent signature:
162 : @code
163 : void( resumer );
164 : @endcode
165 :
166 : @return A @ref route_result equal to @ref route::detach
167 : */
168 : template<class F>
169 : route_result
170 : operator()(F&& f);
171 :
172 : private:
173 : friend resumer;
174 : owner* p_ = nullptr;
175 : };
176 :
177 : //------------------------------------------------
178 :
179 : /** Function to resume a route handler's session
180 :
181 : This holds a reference to an implementation
182 : which resumes the handler's session. The resume
183 : function is returned by calling @ref detach.
184 : */
185 : class resumer
186 : {
187 : public:
188 : /** Constructor
189 :
190 : Default constructed resume functions will
191 : be empty. Invoking an empty resume function
192 : yields undefined behavior.
193 : */
194 : resumer() = default;
195 :
196 : /** Constructor
197 :
198 : Copies of resume functions behave the same
199 : as the original
200 : */
201 : resumer(resumer const&) = default;
202 :
203 : /** Assignment
204 :
205 : Copies of resume functions behave the same
206 : as the original
207 : */
208 : resumer& operator=(resumer const&) = default;
209 :
210 : /** Constructor
211 : */
212 : explicit
213 0 : resumer(
214 : detacher::owner& who) noexcept
215 0 : : p_(&who)
216 : {
217 0 : }
218 :
219 : /** Resume the session
220 :
221 : A session is resumed as if the detached
222 : handler returned the error code in `ec`.
223 :
224 : @param ec The error code to resume with.
225 : */
226 : void operator()(
227 : system::error_code const& ec = {}) const
228 : {
229 : p_->do_resume(ec);
230 : }
231 :
232 : private:
233 : detacher::owner* p_ = nullptr;
234 : };
235 :
236 : template<class F>
237 : auto
238 : detacher::
239 : operator()(F&& f) ->
240 : route_result
241 : {
242 : if(! p_)
243 : detail::throw_logic_error();
244 : std::forward<F>(f)(p_->do_detach());
245 : return route::detach;
246 : }
247 :
248 : //------------------------------------------------
249 :
250 : struct acceptor_config
251 : {
252 : bool is_ssl;
253 : bool is_admin;
254 : };
255 :
256 : /** Request object for HTTP route handlers
257 : */
258 : struct Request
259 : {
260 : /** The mount path of the current router
261 :
262 : This is the portion of the request path
263 : which was matched to select the handler.
264 : The remaining portion is available in
265 : @ref path.
266 : */
267 : core::string_view base_path;
268 :
269 : /** The current pathname, relative to the base path
270 : */
271 : core::string_view path;
272 :
273 : /** The complete request target
274 :
275 : This is the parsed directly from the start
276 : line contained in the HTTP request and is
277 : never modified.
278 : */
279 : urls::url_view url;
280 :
281 : acceptor_config port;
282 : http_proto::request_base const& m;
283 : http_proto::request_parser& pr;
284 :
285 0 : Request(
286 : acceptor_config port_,
287 : http_proto::request_base const& m_,
288 : http_proto::request_parser& pr_)
289 0 : : port(port_)
290 0 : , m(m_)
291 0 : , pr(pr_)
292 : {
293 0 : }
294 : };
295 :
296 : /** Response object for HTTP route handlers
297 : */
298 : struct Response
299 : {
300 : /** Set the status code of the response.
301 : @par Example
302 : @code
303 : res.status(http_proto::status::not_found);
304 : @endcode
305 : @param code The status code to set.
306 : @return A reference to this response.
307 : */
308 : BOOST_BEAST2_DECL
309 : Response&
310 : status(http_proto::status code);
311 :
312 : BOOST_BEAST2_DECL
313 : Response&
314 : set_body(std::string s);
315 :
316 : http_proto::response& m;
317 : http_proto::serializer& sr;
318 :
319 : detacher detach;
320 :
321 : /*
322 : bool send(core::string_view);
323 : bool error(system::error_code);
324 : bool status(http_proto::status);
325 : */
326 :
327 0 : Response(
328 : http_proto::response& m_,
329 : http_proto::serializer& sr_) noexcept
330 0 : : m(m_)
331 0 : , sr(sr_)
332 : {
333 0 : }
334 :
335 : };
336 :
337 : } // beast2
338 : } // boost
339 :
340 : #endif
|