LCOV - code coverage report
Current view: top level - src/server - cors.cpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 54.2 % 59 32 27
Test Date: 2026-06-13 19:44:58 Functions: 90.9 % 11 10 1

           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/cors.hpp>
      11                 : #include <utility>
      12                 : 
      13                 : namespace boost {
      14                 : namespace http {
      15                 : 
      16 HIT           1 : cors::
      17                 : cors(
      18               1 :     cors_options options) noexcept
      19               1 :     : options_(std::move(options))
      20                 : {
      21                 :     // VFALCO TODO Validate the strings in options against RFC
      22               1 : }
      23                 : 
      24                 : namespace {
      25                 : 
      26                 : struct Vary
      27                 : {
      28               1 :     Vary(route_params& rp)
      29               1 :         : rp_(rp)
      30                 :     {
      31               1 :     }
      32                 : 
      33               2 :     void set(field f, core::string_view s)
      34                 :     {
      35               2 :         rp_.res.set(f, s);
      36               2 :     }
      37                 : 
      38 MIS           0 :     void append(field f, core::string_view v)
      39                 :     {
      40               0 :         auto it = rp_.res.find(f);
      41               0 :         if(it != rp_.res.end())
      42                 :         {
      43               0 :             std::string s = it->value;
      44               0 :             s += ", ";
      45               0 :             s += v;
      46               0 :             rp_.res.set(it, s);
      47               0 :         }
      48                 :         else
      49                 :         {
      50               0 :             rp_.res.set(f, v);
      51                 :         }
      52               0 :     }
      53                 : 
      54                 : private:
      55                 :     route_params& rp_;
      56                 : };
      57                 : 
      58                 : } // (anon)
      59                 : 
      60                 : // Access-Control-Allow-Origin
      61 HIT           1 : static void setOrigin(
      62                 :     Vary& v,
      63                 :     route_params const&,
      64                 :     cors_options const& options)
      65                 : {
      66               1 :     if( options.origin.empty() ||
      67 MIS           0 :         options.origin == "*")
      68                 :     {
      69 HIT           1 :         v.set(field::access_control_allow_origin, "*");
      70               1 :         return;
      71                 :     }
      72                 : 
      73 MIS           0 :     v.set(
      74                 :         field::access_control_allow_origin,
      75               0 :         options.origin);
      76               0 :     v.append(field::vary, to_string(field::origin));
      77                 : }
      78                 : 
      79                 : // Access-Control-Allow-Methods
      80 HIT           1 : static void setMethods(
      81                 :     Vary& v,
      82                 :     cors_options const& options)
      83                 : {
      84               1 :     if(! options.methods.empty())
      85                 :     {
      86 MIS           0 :         v.set(
      87                 :             field::access_control_allow_methods,
      88               0 :             options.methods);
      89               0 :         return;
      90                 :     }
      91 HIT           1 :     v.set(
      92                 :         field::access_control_allow_methods,
      93                 :         "GET,HEAD,PUT,PATCH,POST,DELETE");
      94                 : }
      95                 : 
      96                 : // Access-Control-Allow-Credentials
      97               1 : static void setCredentials(
      98                 :     Vary& v,
      99                 :     cors_options const& options)
     100                 : {
     101               1 :     if(! options.credentials)
     102               1 :         return;
     103 MIS           0 :     v.set(
     104                 :         field::access_control_allow_credentials,
     105                 :         "true");
     106                 : }
     107                 : 
     108                 : // Access-Control-Allowed-Headers
     109 HIT           1 : static void setAllowedHeaders(
     110                 :     Vary& v,
     111                 :     route_params const& rp,
     112                 :     cors_options const& options)
     113                 : {
     114               1 :     if(! options.allowedHeaders.empty())
     115                 :     {
     116 MIS           0 :         v.set(
     117                 :             field::access_control_allow_headers,
     118               0 :             options.allowedHeaders);
     119               0 :         return;
     120                 :     }
     121 HIT           1 :     auto s = rp.req.value_or(
     122                 :         field::access_control_request_headers, "");
     123               1 :     if(! s.empty())
     124                 :     {
     125 MIS           0 :         v.set(field::access_control_allow_headers, s);
     126               0 :         v.append(field::vary, s);
     127                 :     }
     128                 : }
     129                 : 
     130                 : // Access-Control-Expose-Headers
     131 HIT           1 : static void setExposeHeaders(
     132                 :     Vary& v,
     133                 :     cors_options const& options)
     134                 : {
     135               1 :     if(options.exposedHeaders.empty())
     136               1 :         return;
     137 MIS           0 :     v.set(
     138                 :         field::access_control_expose_headers,
     139               0 :         options.exposedHeaders);
     140                 : }
     141                 : 
     142                 : // Access-Control-Max-Age
     143 HIT           1 : static void setMaxAge(
     144                 :     Vary& v,
     145                 :     cors_options const& options)
     146                 : {
     147               1 :     if(options.max_age.count() == 0)
     148               1 :         return;
     149 MIS           0 :     v.set(
     150                 :         field::access_control_max_age,
     151               0 :         std::to_string(
     152                 :             options.max_age.count()));
     153                 : }
     154                 : 
     155                 : route_task
     156 HIT           1 : cors::
     157                 : operator()(
     158                 :     route_params& rp) const
     159                 : {
     160                 :     Vary v(rp);
     161                 :     if(rp.req.method() == method::options)
     162                 :     {
     163                 :         // preflight
     164                 :         setOrigin(v, rp, options_);
     165                 :         setMethods(v, options_);
     166                 :         setCredentials(v, options_);
     167                 :         setAllowedHeaders(v, rp, options_);
     168                 :         setMaxAge(v, options_);
     169                 :         setExposeHeaders(v, options_);
     170                 : 
     171                 :         if(options_.preFlightContinue)
     172                 :             co_return route_next;
     173                 : 
     174                 :         // Safari and others need this for 204 or may hang
     175                 :         rp.res.set_status(options_.result);
     176                 :         auto [ec] = co_await rp.send("");
     177                 :         if(ec)
     178                 :             co_return route_error(ec);
     179                 :         co_return route_done;
     180                 :     }
     181                 : 
     182                 :     // actual response
     183                 :     setOrigin(v, rp, options_);
     184                 :     setCredentials(v, options_);
     185                 :     setExposeHeaders(v, options_);
     186                 :     co_return route_next;
     187               2 : }
     188                 : 
     189                 : } // http
     190                 : } // boost
        

Generated by: LCOV version 2.3