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

Generated by: LCOV version 2.3