LCOV - code coverage report
Current view: top level - boost/http/server - route_handler.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 2 0
Test Date: 2026-01-20 00:11:34 Functions: 0.0 % 1 0

            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/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            0 :     write(Buffers const& buffers)
     244              :     {
     245            0 :         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
        

Generated by: LCOV version 2.3