LCOV - code coverage report
Current view: top level - src/server - cors.cpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 91.5 % 59 54
Test Date: 2026-02-09 01:37:05 Functions: 100.0 % 11 11

            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           22 : cors::
      17              : cors(
      18           22 :     cors_options options) noexcept
      19           22 :     : options_(std::move(options))
      20              : {
      21              :     // VFALCO TODO Validate the strings in options against RFC
      22           22 : }
      23              : 
      24              : namespace {
      25              : 
      26              : struct Vary
      27              : {
      28           52 :     Vary(route_params& rp)
      29           52 :         : rp_(rp)
      30              :     {
      31           52 :     }
      32              : 
      33          133 :     void set(field f, core::string_view s)
      34              :     {
      35          133 :         rp_.res.set(f, s);
      36          133 :     }
      37              : 
      38           17 :     void append(field f, core::string_view v)
      39              :     {
      40           17 :         auto it = rp_.res.find(f);
      41           17 :         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           17 :             rp_.res.set(f, v);
      51              :         }
      52           17 :     }
      53              : 
      54              : private:
      55              :     route_params& rp_;
      56              : };
      57              : 
      58              : } // (anon)
      59              : 
      60              : // Access-Control-Allow-Origin
      61           52 : static void setOrigin(
      62              :     Vary& v,
      63              :     route_params const&,
      64              :     cors_options const& options)
      65              : {
      66           69 :     if( options.origin.empty() ||
      67           17 :         options.origin == "*")
      68              :     {
      69           36 :         v.set(field::access_control_allow_origin, "*");
      70           36 :         return;
      71              :     }
      72              : 
      73           16 :     v.set(
      74              :         field::access_control_allow_origin,
      75           16 :         options.origin);
      76           16 :     v.append(field::vary, to_string(field::origin));
      77              : }
      78              : 
      79              : // Access-Control-Allow-Methods
      80           32 : static void setMethods(
      81              :     Vary& v,
      82              :     cors_options const& options)
      83              : {
      84           32 :     if(! options.methods.empty())
      85              :     {
      86            8 :         v.set(
      87              :             field::access_control_allow_methods,
      88            8 :             options.methods);
      89            8 :         return;
      90              :     }
      91           24 :     v.set(
      92              :         field::access_control_allow_methods,
      93              :         "GET,HEAD,PUT,PATCH,POST,DELETE");
      94              : }
      95              : 
      96              : // Access-Control-Allow-Credentials
      97           52 : static void setCredentials(
      98              :     Vary& v,
      99              :     cors_options const& options)
     100              : {
     101           52 :     if(! options.credentials)
     102           36 :         return;
     103           16 :     v.set(
     104              :         field::access_control_allow_credentials,
     105              :         "true");
     106              : }
     107              : 
     108              : // Access-Control-Allowed-Headers
     109           32 : static void setAllowedHeaders(
     110              :     Vary& v,
     111              :     route_params const& rp,
     112              :     cors_options const& options)
     113              : {
     114           32 :     if(! options.allowedHeaders.empty())
     115              :     {
     116            8 :         v.set(
     117              :             field::access_control_allow_headers,
     118            8 :             options.allowedHeaders);
     119            8 :         return;
     120              :     }
     121           24 :     auto s = rp.req.value_or(
     122              :         field::access_control_request_headers, "");
     123           24 :     if(! s.empty())
     124              :     {
     125            1 :         v.set(field::access_control_allow_headers, s);
     126            1 :         v.append(field::vary, s);
     127              :     }
     128              : }
     129              : 
     130              : // Access-Control-Expose-Headers
     131           52 : static void setExposeHeaders(
     132              :     Vary& v,
     133              :     cors_options const& options)
     134              : {
     135           52 :     if(options.exposedHeaders.empty())
     136           36 :         return;
     137           16 :     v.set(
     138              :         field::access_control_expose_headers,
     139           16 :         options.exposedHeaders);
     140              : }
     141              : 
     142              : // Access-Control-Max-Age
     143           32 : static void setMaxAge(
     144              :     Vary& v,
     145              :     cors_options const& options)
     146              : {
     147           32 :     if(options.max_age.count() == 0)
     148           24 :         return;
     149            8 :     v.set(
     150              :         field::access_control_max_age,
     151           16 :         std::to_string(
     152              :             options.max_age.count()));
     153              : }
     154              : 
     155              : route_task
     156           52 : 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          104 : }
     188              : 
     189              : } // http
     190              : } // boost
        

Generated by: LCOV version 2.3