LCOV - code coverage report
Current view: top level - src/server - router_types.cpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 59.1 % 44 26 18
Test Date: 2026-08-26 15:14:03 Functions: 66.7 % 9 6 3

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

Generated by: LCOV version 2.3