GCC Code Coverage Report


Directory: ./
File: libs/http/src/server/cors.cpp
Date: 2026-01-20 00:11:35
Exec Total Coverage
Lines: 0 59 0.0%
Functions: 0 11 0.0%
Branches: 0 37 0.0%

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