Skip to content

Commit f32b39c

Browse files
committed
chore: add sans-io server APIs
1 parent 7971eb2 commit f32b39c

3 files changed

Lines changed: 432 additions & 0 deletions

File tree

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
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/http_proto
8+
//
9+
10+
#ifndef BOOST_HTTP_PROTO_SERVER_ROUTER_TYPES_HPP
11+
#define BOOST_HTTP_PROTO_SERVER_ROUTER_TYPES_HPP
12+
13+
#include <boost/http_proto/detail/config.hpp>
14+
#include <boost/http_proto/method.hpp>
15+
#include <boost/http_proto/detail/except.hpp>
16+
#include <boost/core/detail/string_view.hpp>
17+
#include <boost/system/error_code.hpp>
18+
#include <string>
19+
#include <type_traits>
20+
21+
namespace boost {
22+
namespace http_proto {
23+
24+
/** The result type returned by a route handler.
25+
26+
Route handlers use this type to report errors that prevent
27+
normal processing. A handler must never return a non-failing
28+
(i.e. `ec.failed() == false`) value. Returning a default-constructed
29+
`system::error_code` is disallowed; handlers that complete
30+
successfully must instead return a valid @ref route result.
31+
*/
32+
using route_result = system::error_code;
33+
34+
/** Route handler return values
35+
36+
These values determine how the caller proceeds after invoking
37+
a route handler. Each enumerator represents a distinct control
38+
action—whether the request was handled, should continue to the
39+
next route, transfers ownership of the session, or signals that
40+
the connection should be closed.
41+
*/
42+
enum class route
43+
{
44+
/** The handler requests that the connection be closed.
45+
46+
No further requests will be processed. The caller should
47+
close the connection once the current response, if any,
48+
has been sent.
49+
*/
50+
close = 1,
51+
52+
/** The handler completed the request.
53+
54+
The response has been fully transmitted, and no further
55+
handlers or routes will be invoked. The caller should continue
56+
by either reading the next request on a persistent connection
57+
or closing the session if it is not keep-alive.
58+
*/
59+
complete,
60+
61+
/** The handler detached from the session.
62+
63+
Ownership of the session or stream has been transferred to
64+
the handler. The caller will not perform further I/O or manage
65+
the connection after this return value.
66+
*/
67+
detach,
68+
69+
/** The handler declined to process the request.
70+
71+
The handler chose not to generate a response. The caller
72+
continues invoking the remaining handlers in the same route
73+
until one returns @ref send. If none do, the caller proceeds
74+
to evaluate the next matching route.
75+
76+
This value is returned by @ref basic_router::dispatch if no
77+
handlers in any route handle the request.
78+
*/
79+
next,
80+
81+
/** The handler declined the current route.
82+
83+
The handler wishes to skip any remaining handlers in the
84+
current route and move on to the next matching route. The
85+
caller stops invoking handlers in this route and resumes
86+
evaluation with the next candidate route.
87+
*/
88+
next_route,
89+
90+
/** The request was handled.
91+
92+
The route handler processed the request and prepared
93+
the response serializer. The caller will send the response
94+
before reading the next request or closing the connection.
95+
*/
96+
send
97+
};
98+
99+
//------------------------------------------------
100+
101+
} // http_proto
102+
namespace system {
103+
template<>
104+
struct is_error_code_enum<
105+
::boost::http_proto::route>
106+
{
107+
static bool const value = true;
108+
};
109+
} // system
110+
namespace http_proto {
111+
112+
namespace detail {
113+
struct BOOST_SYMBOL_VISIBLE route_cat_type
114+
: system::error_category
115+
{
116+
BOOST_HTTP_PROTO_DECL const char* name() const noexcept override;
117+
BOOST_HTTP_PROTO_DECL std::string message(int) const override;
118+
BOOST_HTTP_PROTO_DECL char const* message(
119+
int, char*, std::size_t) const noexcept override;
120+
BOOST_SYSTEM_CONSTEXPR route_cat_type()
121+
: error_category(0x51c90d393754ecdf )
122+
{
123+
}
124+
};
125+
BOOST_HTTP_PROTO_DECL extern route_cat_type route_cat;
126+
} // detail
127+
128+
inline
129+
BOOST_SYSTEM_CONSTEXPR
130+
system::error_code
131+
make_error_code(route ev) noexcept
132+
{
133+
return system::error_code{static_cast<
134+
std::underlying_type<route>::type>(ev),
135+
detail::route_cat};
136+
}
137+
138+
/** Return true if `rv` is a route result.
139+
140+
A @ref route_result can hold any error code,
141+
and this function returns `true` only if `rv`
142+
holds a value from the @ref route enumeration.
143+
*/
144+
inline bool is_route_result(
145+
route_result rv) noexcept
146+
{
147+
return &rv.category() == &detail::route_cat;
148+
}
149+
150+
//------------------------------------------------
151+
152+
class resumer;
153+
154+
/** Function to detach a route handler from its session
155+
156+
This holds an reference to an implementation
157+
which detaches the handler from its session.
158+
*/
159+
class detacher
160+
{
161+
public:
162+
/** Base class of the implementation
163+
*/
164+
struct BOOST_SYMBOL_VISIBLE
165+
owner
166+
{
167+
BOOST_HTTP_PROTO_DECL virtual resumer do_detach();
168+
virtual void do_resume(route_result const&) = 0;
169+
};
170+
171+
detacher() = default;
172+
detacher(detacher const&) = default;
173+
detacher& operator=(detacher const&) = default;
174+
175+
explicit
176+
detacher(
177+
owner& who) noexcept
178+
: p_(&who)
179+
{
180+
}
181+
182+
/** Detach and invoke the given function
183+
184+
The function will be invoked with this equivalent signature:
185+
@code
186+
void( resumer );
187+
@endcode
188+
189+
@return A @ref route_result equal to @ref route::detach
190+
*/
191+
template<class F>
192+
route_result
193+
operator()(F&& f);
194+
195+
private:
196+
friend resumer;
197+
owner* p_ = nullptr;
198+
};
199+
200+
//------------------------------------------------
201+
202+
/** Function to resume a route handler's session
203+
204+
This holds a reference to an implementation
205+
which resumes the handler's session. The resume
206+
function is returned by calling @ref detach.
207+
*/
208+
class resumer
209+
{
210+
public:
211+
/** Constructor
212+
213+
Default constructed resume functions will
214+
be empty. An exception is thrown when
215+
attempting to invoke an empty object.
216+
*/
217+
resumer() = default;
218+
219+
/** Constructor
220+
221+
Copies of resume functions behave the same
222+
as the original
223+
*/
224+
resumer(resumer const&) = default;
225+
226+
/** Assignment
227+
228+
Copies of resume functions behave the same
229+
as the original
230+
*/
231+
resumer& operator=(resumer const&) = default;
232+
233+
/** Constructor
234+
*/
235+
explicit
236+
resumer(
237+
detacher::owner& who) noexcept
238+
: p_(&who)
239+
{
240+
}
241+
242+
/** Resume the session
243+
244+
A session is resumed as if the detached
245+
handler returned the route result in @p rv.
246+
247+
@param ec The error code to resume with.
248+
249+
@throw std::invalid_argument If the object is empty.
250+
*/
251+
void operator()(
252+
route_result const& rv) const
253+
{
254+
if(! p_)
255+
detail::throw_invalid_argument();
256+
p_->do_resume(rv);
257+
}
258+
259+
private:
260+
detacher::owner* p_ = nullptr;
261+
};
262+
263+
template<class F>
264+
auto
265+
detacher::
266+
operator()(F&& f) ->
267+
route_result
268+
{
269+
if(! p_)
270+
detail::throw_logic_error();
271+
std::forward<F>(f)(p_->do_detach());
272+
return route::detach;
273+
}
274+
275+
//------------------------------------------------
276+
277+
namespace detail {
278+
class any_router;
279+
} // detail
280+
template<class, class>
281+
class basic_router;
282+
283+
/** Base class for request objects
284+
285+
This is a required public base for any `Request`
286+
type used with @ref basic_router.
287+
*/
288+
class basic_request
289+
{
290+
public:
291+
/** The mount path of the current router
292+
293+
This is the portion of the request path
294+
which was matched to select the handler.
295+
The remaining portion is available in
296+
@ref path.
297+
*/
298+
core::string_view base_path;
299+
300+
/** The current pathname, relative to the base path
301+
*/
302+
core::string_view path;
303+
304+
private:
305+
friend class /*detail::*/any_router;
306+
struct match_result;
307+
http_proto::method verb_ =
308+
http_proto::method::unknown;
309+
std::string verb_str_;
310+
std::string decoded_path_;
311+
bool addedSlash_ = false;
312+
bool case_sensitive = false;
313+
bool strict = false;
314+
};
315+
316+
//-----------------------------------------------
317+
318+
/** Base class for response objects
319+
320+
This is a required public base for any `Response`
321+
type used with @ref basic_router.
322+
*/
323+
class basic_response
324+
{
325+
private:
326+
friend class /*detail::*/any_router;
327+
template<class, class>
328+
friend class basic_router;
329+
330+
std::size_t pos_ = 0;
331+
std::size_t resume_ = 0;
332+
system::error_code ec_;
333+
unsigned int opt_ = 0;
334+
};
335+
336+
} // http_proto
337+
} // boost
338+
339+
#endif

0 commit comments

Comments
 (0)