LCOV - code coverage report
Current view: top level - src/server - router_types.cpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 55.6 % 45 25
Test Date: 2026-02-09 01:37:05 Functions: 60.0 % 10 6

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

Generated by: LCOV version 2.3