LCOV - code coverage report
Current view: top level - libs/http/src/server - router_types.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 51.1 % 45 23
Test Date: 2026-02-02 17:02:49 Functions: 50.0 % 10 5

            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 <boost/http/server/router_types.hpp>
      11              : #include <boost/http/server/router.hpp>
      12              : #include <boost/http/server/etag.hpp>
      13              : #include <boost/http/server/fresh.hpp>
      14              : #include <boost/http/detail/except.hpp>
      15              : #include <boost/url/grammar/ci_string.hpp>
      16              : #include <boost/capy/buffers/make_buffer.hpp>
      17              : #include <boost/assert.hpp>
      18              : #include <cstring>
      19              : 
      20              : namespace boost {
      21              : namespace system {
      22              : template<>
      23              : struct is_error_code_enum<
      24              :     ::boost::http::route_what>
      25              : {
      26              :     static bool const value = true;
      27              : };
      28              : } // system
      29              : } // boost
      30              : 
      31              : namespace boost {
      32              : namespace http {
      33              : 
      34              : namespace {
      35              : 
      36              : struct route_what_cat_type
      37              :     : system::error_category
      38              : {
      39              :     constexpr route_what_cat_type()
      40              :         : error_category(0x7a8b3c4d5e6f1029)
      41              :     {
      42              :     }
      43              : 
      44            0 :     const char* name() const noexcept override
      45              :     {
      46            0 :         return "boost.http.route_what";
      47              :     }
      48              : 
      49            0 :     std::string message(int code) const override
      50              :     {
      51            0 :         return message(code, nullptr, 0);
      52              :     }
      53              : 
      54            0 :     char const* message(
      55              :         int code,
      56              :         char*,
      57              :         std::size_t) const noexcept override
      58              :     {
      59            0 :         switch(static_cast<route_what>(code))
      60              :         {
      61            0 :         case route_what::done:          return "done";
      62            0 :         case route_what::error:         return "error";
      63            0 :         case route_what::next:          return "next";
      64            0 :         case route_what::next_route:    return "next_route";
      65            0 :         case route_what::close:         return "close";
      66            0 :         default:
      67            0 :             return "?";
      68              :         }
      69              :     }
      70              : };
      71              : 
      72              : route_what_cat_type route_what_cat;
      73              : 
      74              : } // (anon)
      75              : 
      76              : system::error_code
      77          150 : make_error_code(
      78              :     route_what w) noexcept
      79              : {
      80              :     return system::error_code{
      81          150 :         static_cast<int>(w), route_what_cat};
      82              : }
      83              : 
      84              : //----------------------------------------------------------
      85              : 
      86           13 : route_result::
      87              : route_result(
      88           13 :     system::error_code ec)
      89           13 :     : ec_(ec)
      90              : {
      91           13 :     if(! ec.failed())
      92            0 :         detail::throw_invalid_argument();
      93           13 : }
      94              : 
      95              : void
      96          120 : route_result::
      97              : set(route_what w)
      98              : {
      99          120 :     ec_ = make_error_code(w);
     100          120 : }
     101              : 
     102              : auto
     103          428 : route_result::
     104              : what() const noexcept ->
     105              :     route_what
     106              : {
     107          428 :     if(! ec_.failed())
     108          362 :         return route_what::done;    
     109           66 :     if(&ec_.category() != &route_what_cat)
     110           40 :         return route_what::error;
     111           26 :     if( ec_ == route_what::next)
     112           22 :         return route_what::next;
     113            4 :     if( ec_ == route_what::next_route)
     114            3 :         return route_what::next_route;
     115              :     //if( ec_ == route_what::close)
     116            1 :     return route_what::close;
     117              : }
     118              : 
     119              : auto
     120            9 : route_result::
     121              : error() const noexcept ->
     122              :     system::error_code
     123              : {
     124            9 :     if(&ec_.category() != &route_what_cat)
     125            9 :         return ec_;
     126            0 :     return {};
     127              : }
     128              : 
     129              : //------------------------------------------------
     130              : 
     131              : bool
     132            0 : route_params_base::
     133              : is_method(
     134              :     core::string_view s) const noexcept
     135              : {
     136            0 :     auto m = http::string_to_method(s);
     137            0 :     if(m != http::method::unknown)
     138            0 :         return verb_ == m;
     139            0 :     return s == verb_str_;
     140              : }
     141              : 
     142              : //------------------------------------------------
     143              : 
     144              : capy::io_task<>
     145            0 : route_params::
     146              : send(std::string_view body)
     147              : {
     148              :     auto const sc = res.status();
     149              : 
     150              :     // 204 No Content / 304 Not Modified: strip headers, no body
     151              :     if(sc == status::no_content ||
     152              :        sc == status::not_modified)
     153              :     {
     154              :         res.erase(field::content_type);
     155              :         res.erase(field::content_length);
     156              :         res.erase(field::transfer_encoding);
     157              :         co_return co_await res_body.write_eof();
     158              :     }
     159              : 
     160              :     // 205 Reset Content: Content-Length=0, no body
     161              :     if(sc == status::reset_content)
     162              :     {
     163              :         res.erase(field::transfer_encoding);
     164              :         res.set_payload_size(0);
     165              :         co_return co_await res_body.write_eof();
     166              :     }
     167              : 
     168              :     // Set Content-Type if not already set
     169              :     if(! res.exists(field::content_type))
     170              :     {
     171              :         if(! body.empty() && body[0] == '<')
     172              :             res.set(field::content_type,
     173              :                 "text/html; charset=utf-8");
     174              :         else
     175              :             res.set(field::content_type,
     176              :                 "text/plain; charset=utf-8");
     177              :     }
     178              : 
     179              :     // Generate ETag if not already set
     180              :     if(! res.exists(field::etag))
     181              :         res.set(field::etag, etag(body));
     182              : 
     183              :     // Set Content-Length if not already set
     184              :     if(! res.exists(field::content_length))
     185              :         res.set_payload_size(body.size());
     186              : 
     187              :     // Freshness check: auto-304 for conditional GET
     188              :     if(is_fresh(req, res))
     189              :     {
     190              :         res.set_status(status::not_modified);
     191              :         res.erase(field::content_type);
     192              :         res.erase(field::content_length);
     193              :         res.erase(field::transfer_encoding);
     194              :         co_return co_await res_body.write_eof();
     195              :     }
     196              : 
     197              :     // HEAD: send headers only, skip body
     198              :     if(req.method() == method::head)
     199              :     {
     200              :         co_return co_await res_body.write_eof();
     201              :     }
     202              : 
     203              :     auto [ec, n] = co_await res_body.write(
     204              :         capy::make_buffer(body), true);
     205              :     co_return {ec};
     206            0 : }
     207              : 
     208              : } // http
     209              : } // boost
        

Generated by: LCOV version 2.3