GCC Code Coverage Report


Directory: ./
File: libs/http/include/boost/http/server/route_handler.hpp
Date: 2026-01-20 00:11:35
Exec Total Coverage
Lines: 0 2 0.0%
Functions: 0 1 0.0%
Branches: 0 1 0.0%

Line Branch Exec Source
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
8 //
9
10 #ifndef BOOST_HTTP_SERVER_ROUTE_HANDLER_HPP
11 #define BOOST_HTTP_SERVER_ROUTE_HANDLER_HPP
12
13 #include <boost/http/detail/config.hpp>
14 #include <boost/http/server/router_types.hpp>
15 #include <boost/capy/any_bufref.hpp>
16 #include <boost/capy/buffers.hpp>
17 #include <boost/capy/datastore.hpp>
18 #include <boost/capy/task.hpp>
19 #include <boost/http/request.hpp> // VFALCO forward declare?
20 #include <boost/http/request_parser.hpp> // VFALCO forward declare?
21 #include <boost/http/response.hpp> // VFALCO forward declare?
22 #include <boost/http/serializer.hpp> // VFALCO forward declare?
23 #include <boost/url/url_view.hpp>
24 #include <boost/system/error_code.hpp>
25 #include <memory>
26
27 namespace boost {
28 namespace http {
29
30 struct acceptor_config
31 {
32 bool is_ssl;
33 bool is_admin;
34 };
35
36 //-----------------------------------------------
37
38 /** The coroutine task type returned by route handlers.
39
40 Route handlers are coroutines that process HTTP requests and
41 must return this type. The underlying @ref route_result
42 (a `system::error_code`) communicates the routing disposition
43 back to the router:
44
45 @li Return @ref route::next to decline handling and allow
46 subsequent handlers in the same route to process the request.
47
48 @li Return @ref route::next_route to skip remaining handlers
49 in the current route and proceed to the next matching route.
50
51 @li Return a non-failing code (one for which
52 `error_code::failed()` returns `false`) to indicate the
53 response is complete. The connection will either close
54 or proceed to the next request.
55
56 @li Return a failing error code to signal an error that
57 prevents normal processing.
58
59 @par Example
60 @code
61 // A handler that serves static files
62 route_task serve_file(route_params& p)
63 {
64 auto path = find_file(p.path);
65 if(path.empty())
66 co_return route::next; // Not found, try next handler
67
68 p.res.set_body_file(path);
69 co_return {}; // Success
70 }
71
72 // A handler that requires authentication
73 route_task require_auth(route_params& p)
74 {
75 if(! p.session_data.contains<user_session>())
76 {
77 p.status(http::status::unauthorized);
78 co_return {};
79 }
80 co_return route::next; // Authenticated, continue chain
81 }
82 @endcode
83
84 @see @ref route_result, @ref route, @ref route_params
85 */
86 using route_task = capy::task<route_result>;
87
88 //-----------------------------------------------
89
90 /** Parameters object for HTTP route handlers
91 */
92 struct BOOST_HTTP_SYMBOL_VISIBLE
93 route_params : route_params_base
94 {
95 /** The complete request target
96
97 This is the parsed directly from the start
98 line contained in the HTTP request and is
99 never modified.
100 */
101 urls::url_view url;
102
103 /** The HTTP request message
104 */
105 http::request req;
106
107 /** The HTTP response message
108 */
109 http::response res;
110
111 /** The HTTP request parser
112 This can be used to take over reading the body.
113 */
114 http::request_parser parser;
115
116 /** The HTTP response serializer
117 */
118 http::serializer serializer;
119
120 /** A container for storing arbitrary data associated with the request.
121 This starts out empty for each new request.
122 */
123 capy::datastore route_data;
124
125 /** A container for storing arbitrary data associated with the session.
126
127 This starts out empty for each new session.
128 */
129 capy::datastore session_data;
130
131 /** Destructor
132 */
133 BOOST_HTTP_DECL
134 ~route_params();
135
136 /** Reset the object for a new request.
137 This clears any state associated with
138 the previous request, preparing the object
139 for use with a new request.
140 */
141 BOOST_HTTP_DECL
142 void reset();
143
144 /** Set the status code of the response.
145 @par Example
146 @code
147 res.status( http::status::not_found );
148 @endcode
149 @param code The status code to set.
150 @return A reference to this response.
151 */
152 BOOST_HTTP_DECL
153 route_params&
154 status(http::status code);
155
156 BOOST_HTTP_DECL
157 route_params&
158 set_body(std::string s);
159
160 /** Send the HTTP response with the given body.
161
162 This convenience coroutine handles the entire response
163 lifecycle in a single call, similar to Express.js
164 `res.send()`. It performs the following steps:
165
166 @li Sets the response body to the provided string.
167 @li Sets the `Content-Length` header automatically.
168 @li If `Content-Type` is not already set, detects the
169 type: bodies starting with `<` are sent as
170 `text/html; charset=utf-8`, otherwise as
171 `text/plain; charset=utf-8`.
172 @li Serializes and transmits the complete response.
173
174 After calling this function the response is complete.
175 Do not attempt to modify or send additional data.
176
177 @par Example
178 @code
179 // Plain text (no leading '<')
180 route_task hello( route_params& rp )
181 {
182 co_return co_await rp.send( "Hello, World!" );
183 }
184
185 // HTML (starts with '<')
186 route_task greeting( route_params& rp )
187 {
188 co_return co_await rp.send( "<h1>Welcome</h1>" );
189 }
190
191 // Explicit Content-Type for JSON
192 route_task api( route_params& rp )
193 {
194 rp.res.set( http::field::content_type, "application/json" );
195 co_return co_await rp.send( R"({"status":"ok"})" );
196 }
197 @endcode
198
199 @param body The content to send as the response body.
200
201 @return A @ref route_task that completes when the response
202 has been fully transmitted, yielding a @ref route_result
203 indicating success or failure.
204 */
205 virtual route_task send(std::string_view body) = 0;
206
207 /** Write buffer data to the response body.
208
209 This coroutine writes the provided buffer sequence to
210 the response output stream. It is used for streaming
211 responses where the body is sent in chunks.
212
213 The response headers must be set appropriately before
214 calling this function (e.g., set Transfer-Encoding to
215 chunked, or set Content-Length if known).
216
217 @par Example
218 @code
219 route_task stream_response( route_params& rp )
220 {
221 rp.res.set( field::transfer_encoding, "chunked" );
222
223 // Write in chunks
224 std::string chunk1 = "Hello, ";
225 co_await rp.write( capy::const_buffer(
226 chunk1.data(), chunk1.size() ) );
227
228 std::string chunk2 = "World!";
229 co_await rp.write( capy::const_buffer(
230 chunk2.data(), chunk2.size() ) );
231
232 co_return co_await rp.end();
233 }
234 @endcode
235
236 @param buffers A buffer sequence containing the data to write.
237
238 @return A @ref route_task that completes when the write
239 operation is finished.
240 */
241 template<capy::ConstBufferSequence Buffers>
242 route_task
243 write(Buffers const& buffers)
244 {
245 return write_impl(capy::any_bufref(buffers));
246 }
247
248 /** Complete a streaming response.
249
250 This coroutine finalizes a streaming response that was
251 started with @ref write calls. For chunked transfers,
252 it sends the final chunk terminator.
253
254 @par Example
255 @code
256 route_task send_file( route_params& rp )
257 {
258 rp.res.set( field::transfer_encoding, "chunked" );
259
260 // Stream file contents...
261 while( ! file.eof() )
262 {
263 auto data = file.read();
264 co_await rp.write( capy::const_buffer(
265 data.data(), data.size() ) );
266 }
267
268 co_return co_await rp.end();
269 }
270 @endcode
271
272 @return A @ref route_task that completes when the response
273 has been fully finalized.
274 */
275 virtual route_task end() = 0;
276
277 protected:
278 /** Implementation of write with type-erased buffers.
279
280 Derived classes must implement this to perform the
281 actual write operation.
282
283 @param buffers Type-erased buffer sequence.
284
285 @return A task that completes when the write is done.
286 */
287 virtual route_task write_impl(capy::any_bufref buffers) = 0;
288 };
289
290 } // http
291 } // boost
292
293 #endif
294