LCOV - code coverage report
Current view: top level - libs/http/src/server/detail - router_base.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 88.2 % 68 60
Test Date: 2026-01-20 00:11:34 Functions: 90.9 % 11 10

            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              : #include "src/server/detail/router_base.hpp"
      11              : #include <boost/http/server/detail/router_base.hpp>
      12              : #include <boost/http/server/flat_router.hpp>
      13              : #include <boost/http/server/route_handler.hpp>
      14              : #include <boost/http/detail/except.hpp>
      15              : #include <boost/url/grammar/ci_string.hpp>
      16              : #include <boost/url/grammar/hexdig_chars.hpp>
      17              : #include "src/server/detail/route_match.hpp"
      18              : #include "src/server/detail/route_rule.hpp"
      19              : 
      20              : /*
      21              : 
      22              : pattern     target      path(use)    path(get) 
      23              : -------------------------------------------------
      24              : /           /           /
      25              : /           /api        /api
      26              : /api        /api        /            /api
      27              : /api        /api/       /            /api/
      28              : /api        /api/       /            no-match       strict
      29              : /api        /api/v0     /v0          no-match
      30              : /api/       /api        /            /api
      31              : /api/       /api        /            no-match       strict
      32              : /api/       /api/       /            /api/
      33              : /api/       /api/v0     /v0          no-match
      34              : 
      35              : */
      36              : 
      37              : namespace boost {
      38              : namespace http {
      39              : namespace detail {
      40              : 
      41          182 : router_base::
      42              : ~router_base()
      43              : {
      44          182 :     delete impl_;
      45          182 : }
      46              : 
      47          102 : router_base::
      48              : router_base(
      49          102 :     opt_flags opt)
      50          102 :     : impl_(new impl(opt))
      51              : {
      52          102 : }
      53              : 
      54           80 : router_base::
      55              : router_base(
      56           80 :     router_base&& other) noexcept
      57           80 :     :impl_(other.impl_)
      58              : {
      59           80 :     other.impl_ = nullptr;
      60           80 : }
      61              : 
      62              : router_base&
      63            0 : router_base::
      64              : operator=(
      65              :     router_base&& other) noexcept
      66              : {
      67            0 :     delete impl_;
      68            0 :     impl_ = other.impl_;
      69            0 :     other.impl_ = 0;
      70            0 :     return *this;
      71              : }
      72              : 
      73              : auto
      74           27 : router_base::
      75              : new_layer(
      76              :     std::string_view pattern) -> layer&
      77              : {
      78              :     // the pattern must not be empty
      79           27 :     if(pattern.empty())
      80            0 :         detail::throw_invalid_argument();
      81              :     // delete the last route if it is empty,
      82              :     // this happens if they call route() without
      83              :     // adding anything
      84           30 :     if(! impl_->layers.empty() &&
      85            3 :         impl_->layers.back().entries.empty())
      86            0 :         impl_->layers.pop_back();
      87           27 :     impl_->layers.emplace_back(pattern);
      88           27 :     return impl_->layers.back();
      89              : };
      90              : 
      91              : std::size_t
      92           27 : router_base::
      93              : new_layer_idx(
      94              :     std::string_view pattern)
      95              : {
      96           27 :     new_layer(pattern);
      97           27 :     return impl_->layers.size() - 1;
      98              : }
      99              : 
     100              : auto
     101           30 : router_base::
     102              : get_layer(
     103              :     std::size_t idx) -> layer&
     104              : {
     105           30 :     return impl_->layers[idx];
     106              : }
     107              : 
     108              : void
     109           89 : router_base::
     110              : add_impl(
     111              :     std::string_view pattern,
     112              :     handlers hn)
     113              : {
     114           89 :     if( pattern.empty())
     115           22 :         pattern = "/";
     116           89 :     impl_->layers.emplace_back(
     117              :         pattern, hn);
     118              : 
     119              :     // Validate depth for any nested routers
     120           89 :     auto& lay = impl_->layers.back();
     121          186 :     for(auto& entry : lay.entries)
     122           98 :         if(entry.h->kind == is_router)
     123           40 :             if(auto* r = entry.h->get_router())
     124           40 :                 r->set_nested_depth(impl_->depth_);
     125           88 : }
     126              : 
     127              : void
     128           22 : router_base::
     129              : add_impl(
     130              :     layer& l,
     131              :     http::method verb,
     132              :     handlers hn)
     133              : {
     134              :     // cannot be unknown
     135           22 :     if(verb == http::method::unknown)
     136            0 :         detail::throw_invalid_argument();
     137              : 
     138           22 :     l.entries.reserve(l.entries.size() + hn.n);
     139           45 :     for(std::size_t i = 0; i < hn.n; ++i)
     140           23 :         l.entries.emplace_back(verb,
     141           23 :             std::move(hn.p[i]));
     142           22 : }
     143              : 
     144              : void
     145            8 : router_base::
     146              : add_impl(
     147              :     layer& l,
     148              :     std::string_view verb_str,
     149              :     handlers hn)
     150              : {
     151            8 :     l.entries.reserve(l.entries.size() + hn.n);
     152              : 
     153            8 :     if(verb_str.empty())
     154              :     {
     155              :         // all
     156           12 :         for(std::size_t i = 0; i < hn.n; ++i)
     157            6 :             l.entries.emplace_back(std::move(hn.p[i]));
     158            6 :         return;
     159              :     }
     160              : 
     161              :     // possibly custom string
     162            4 :     for(std::size_t i = 0; i < hn.n; ++i)
     163            2 :         l.entries.emplace_back(verb_str,
     164            2 :             std::move(hn.p[i]));
     165              : }
     166              : 
     167              : void
     168          266 : router_base::
     169              : set_nested_depth(
     170              :     std::size_t parent_depth)
     171              : {
     172          266 :     std::size_t d = parent_depth + 1;
     173          266 :     if(d >= max_path_depth)
     174            1 :         detail::throw_length_error(
     175              :             "router nesting depth exceeds max_path_depth");
     176          265 :     impl_->depth_ = d;
     177          515 :     for(auto& layer : impl_->layers)
     178          515 :         for(auto& entry : layer.entries)
     179          265 :             if(entry.h->kind == is_router)
     180          226 :                 if(auto* r = entry.h->get_router())
     181          226 :                     r->set_nested_depth(d);
     182          250 : }
     183              : 
     184              : } // detail
     185              : } // http
     186              : } // boost
     187              : 
        

Generated by: LCOV version 2.3