LCOV - code coverage report
Current view: top level - boost/beast2/server/basic_router.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 83.3 % 30 25
Test Date: 2025-11-13 15:50:43 Functions: 73.3 % 15 11

            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_BASIC_ROUTER_HPP
      11              : #define BOOST_BEAST2_SERVER_BASIC_ROUTER_HPP
      12              : 
      13              : #include <boost/beast2/detail/config.hpp>
      14              : #include <boost/beast2/server/detail/any_router.hpp>
      15              : #include <boost/beast2/detail/call_traits.hpp>
      16              : #include <boost/beast2/detail/type_traits.hpp>
      17              : #include <boost/http_proto/method.hpp>
      18              : #include <boost/url/url_view.hpp>
      19              : #include <boost/core/detail/string_view.hpp>
      20              : #include <type_traits>
      21              : 
      22              : namespace boost {
      23              : namespace beast2 {
      24              : 
      25              : struct route_state
      26              : {
      27              : private:
      28              :     friend class detail::any_router;
      29              :     template<class, class>
      30              :     friend class basic_router;
      31              : 
      32              :     std::size_t pos = 0;
      33              :     std::size_t resume = 0;
      34              :     route_result ec;
      35              :     http_proto::method verb;
      36              :     core::string_view verb_str;
      37              :     std::string decoded_path;
      38              : };
      39              : 
      40              : //------------------------------------------------
      41              : 
      42              : /** A container for HTTP route handlers
      43              : 
      44              :     The basic_router class template is used to
      45              :     store and invoke route handlers based on
      46              :     the request method and path.
      47              :     Handlers are added to the router using
      48              :     the member functions such as @ref get,
      49              :     @ref post, and @ref all.
      50              :     Handlers are invoked by calling the
      51              :     function call operator with a request
      52              :     and response object.
      53              : 
      54              :     Express treats all route definitions as decoded path patterns, not raw URL-encoded ones.
      55              :     So a literal %2F in the pattern string is indistinguishable from a literal / once Express builds the layer.
      56              :     Therefore "/x%2Fz" is the same as "/x/z"
      57              : 
      58              :     @par Example
      59              :     @code
      60              :     using router_type = basic_router<Req, Res>;
      61              :     router_type router;
      62              :     router.get("/hello",
      63              :         [](Req& req, Res& res)
      64              :         {
      65              :             res.status(http_proto::status::ok);
      66              :             res.set_body("Hello, world!");
      67              :             return system::error_code{};
      68              :         });
      69              :     @endcode
      70              : 
      71              :     @tparam Req The type of request object.
      72              :     @tparam Res The type of response object.
      73              : */
      74              : template<class Req, class Res>
      75              : class basic_router : public detail::any_router
      76              : {
      77              :     static constexpr http_proto::method
      78              :         middleware = http_proto::method::unknown;
      79              : 
      80              : public:
      81              :     /** The type of request object used in handlers
      82              : 
      83              :         Route handlers must have this invocable signature
      84              :         @code
      85              :         system::error_code(Req&, Res&)
      86              :         @endcode
      87              :     */
      88              :     using request_type = Req;
      89              : 
      90              :     /** The type of response object used in handlers
      91              : 
      92              :         Route handlers must have this invocable signature
      93              :         @code
      94              :         system::error_code(Req&, Res&)
      95              :         @endcode
      96              :     */
      97              :     using response_type = Res;
      98              : 
      99              :     /** Constructor
     100              :     */
     101            7 :     basic_router()
     102              :         : any_router(
     103           21 :             [](void* preq) -> req_info
     104              :             {
     105           14 :                 auto& req = *reinterpret_cast<Req*>(preq);
     106           14 :                 return req_info{ req.base_path, req.path };
     107            7 :             })
     108              :     {
     109            7 :     }
     110              : 
     111              :     /** Constructor
     112              :     */
     113              :     template<
     114              :         class OtherReq, class OtherRes,
     115              :         class = typename std::enable_if<
     116              :             detail::derived_from<Req, OtherReq>::value &&
     117              :             detail::derived_from<Res, OtherRes>::value>::type
     118              :     >
     119              :     basic_router(
     120              :         basic_router<OtherReq, OtherRes> const& other)
     121              :         : any_router(other)
     122              :     {
     123              :     }
     124              : 
     125              :     /** Add one or more global middleware handlers.
     126              : 
     127              :         Each handler registered with this function runs for every incoming
     128              :         request, regardless of its HTTP method or path. Handlers execute in
     129              :         the order they were added, and may call `next()` to transfer control
     130              :         to the subsequent handler in the chain.
     131              : 
     132              :         This is equivalent to writing
     133              :         @code
     134              :         use( "/", h1, hn... );
     135              :         @endcode
     136              :     */
     137              :     template<class H1, class... HN
     138              :         , class = typename std::enable_if<! std::is_convertible<
     139              :             H1, core::string_view>::value>::type
     140              :     >
     141            1 :     void use(H1&& h1, HN&&... hn)
     142              :     {
     143            1 :         use("/", std::forward<H1>(h1), std::forward<HN>(hn)...);
     144            1 :     }
     145              : 
     146              :     /** Add one or more middleware handlers for a path prefix.
     147              : 
     148              :         Each handler registered with this function runs for every request
     149              :         whose path begins with the specified prefix, regardless of the
     150              :         request method. The prefix match is not strict: middleware attached
     151              :         to `"/api"` will also match `"/api/users"` and `"/api/data"`.
     152              :         Handlers execute in the order they were added, and may call `next()`
     153              :         to transfer control to the subsequent handler.
     154              : 
     155              :         This function behaves analogously to `app.use(path, ...)` in
     156              :         Express.js. The registered middleware executes for requests matching
     157              :         the prefix, and when registered before route handlers for the same
     158              :         prefix, runs prior to those routes.
     159              : 
     160              :         @par Example
     161              :         @code
     162              :         router.use("/api",
     163              :             [](Request& req, Response& res)
     164              :             {
     165              :                 if(!authenticate(req))
     166              :                     return res.setStatus(401), res.end("Unauthorized");
     167              :                 return res.next();
     168              :             },
     169              :             [](Request&, Response& res)
     170              :             {
     171              :                 res.setHeader("X-Powered-By", "MyServer");
     172              :             });
     173              :         @endcode
     174              : 
     175              :         @par Constraints
     176              :         - `pattern` must be a valid path prefix; it may be empty to indicate
     177              :           the root scope.
     178              :         - Each handler must be callable with the signature  
     179              :           `void(Request&, Response&, NextHandler)`.
     180              :         - Each handler must be copy- or move-constructible, depending on how
     181              :           it is passed.
     182              : 
     183              :         @throws Any exception thrown by a handler during execution.
     184              : 
     185              :         @param pattern  The path prefix to match. Middleware runs for any
     186              :             request whose path begins with this prefix.
     187              :         @param h0  The first middleware handler to install.
     188              :         @param hn  Additional middleware handlers to install, executed in
     189              :             declaration order.
     190              : 
     191              :         @return (none)
     192              :     */
     193              :     template<class H0, class... HN>
     194            9 :     void use(
     195              :         core::string_view pattern,
     196              :         H0&& h0, HN... hn)
     197              :     {
     198            9 :         if(pattern.empty())
     199            0 :             pattern = "/";
     200            9 :         append(false, middleware, pattern,
     201              :             std::forward<H0>(h0),
     202              :             std::forward<HN>(hn)...);
     203            9 :     }
     204              : 
     205              :     template<class H0, class... HN>
     206              :     void add(
     207              :         http_proto::method method,
     208              :         core::string_view pattern,
     209              :         H0&& h0, HN&&... hn)
     210              :     {
     211              :         append(false, method, pattern,
     212              :             std::forward<H0>(h0),
     213              :             std::forward<HN>(hn)...);
     214              :     }
     215              : 
     216              :     /** Add an error handler
     217              :     */
     218              :     template<class H0, class... HN>
     219              :     void err(
     220              :         H0&& h0, HN&&... hn)
     221              :     {
     222              :         append_err(
     223              :             std::forward<H0>(h0),
     224              :             std::forward<HN>(hn)...);
     225              :     }
     226              : 
     227              :     /** Add a route handler matching all methods and the given pattern
     228              :         The handler will run for every request matching the entire pattern.
     229              :     */
     230              :     template<class H0, class... HN>
     231              :     void all(
     232              :         core::string_view pattern,
     233              :         H0&& h0, HN&&... hn)
     234              :     {
     235              :         return add(middleware, pattern,
     236              :             std::forward<H0>(h0), std::forward<HN>(hn)...);
     237              :     }
     238              : 
     239              :     /** Add a GET handler
     240              :     */
     241              :     template<class H0, class... HN>
     242              :     void get(
     243              :         core::string_view pattern,
     244              :         H0&& h0, HN&&... hn)
     245              :     {
     246              :         add(http_proto::method::get, pattern,
     247              :             std::forward<H0>(h0), std::forward<HN>(hn)...);
     248              :     }
     249              : 
     250              :     template<class H0, class... HN>
     251              :     void post(
     252              :         core::string_view pattern,
     253              :         H0&& h0, HN&&... hn)
     254              :     {
     255              :         add(http_proto::method::post, pattern,
     256              :             std::forward<H0>(h0), std::forward<HN>(hn)...);
     257              :     }
     258              : 
     259            7 :     auto dispatch(
     260              :         http_proto::method method,
     261              :         urls::url_view const& url,
     262              :         Req& req, Res& res, route_state& st) ->
     263              :             route_result
     264              :     {
     265            7 :         return dispatch_impl(
     266            7 :             method, url, &req, &res, st);
     267              :     }
     268              : 
     269              :     auto
     270            0 :     resume(
     271              :         Req& req,
     272              :         Res& res,
     273              :         route_result const& ec,
     274              :         route_state& st) const ->
     275              :             route_result
     276              :     {
     277            0 :         st.pos = 0;
     278            0 :         st.ec = ec;
     279            0 :         return dispatch_impl(&req, &res, st);
     280              :     }
     281              : 
     282              : private:
     283              :     template<class H>
     284            9 :     handler_ptr make_handler(H&& h)
     285              :     {
     286           18 :         return handler_ptr(new handler_impl<
     287           18 :             Req, Res, H>(std::forward<H>(h)));
     288              :     }
     289              : 
     290            9 :     void append(bool, http_proto::method,
     291              :         core::string_view) const noexcept
     292              :     {
     293            9 :     }
     294              : 
     295              :     template<class H0, class... HN>
     296            9 :     void append(bool prefix, http_proto::method method,
     297              :         core::string_view pat, H0&& h, HN&&... hn)
     298              :     {
     299            9 :         any_router::append(prefix, method, pat,
     300              :             make_handler<H0>(std::forward<H0>(h)));
     301            9 :         append(prefix, method, pat, std::forward<HN>(hn)...);
     302            9 :     }
     303              : 
     304              :     template<class H0, class... HN>
     305              :     void append_err(H0&& h, HN&&... hn)
     306              :     {
     307              :         append(true, middleware, {},
     308              :             std::forward<H0>(h),
     309              :             std::forward<HN>(hn)...);
     310              :     }
     311              : };
     312              : 
     313              : } // beast2
     314              : } // boost
     315              : 
     316              : #endif
        

Generated by: LCOV version 2.1