Crow  1.1
A C++ microframework for the web
cors.h
1 #pragma once
2 #include "crow/http_request.h"
3 #include "crow/http_response.h"
4 #include "crow/routing.h"
5 
6 namespace crow
7 {
8  struct CORSHandler;
9 
10  /// Used for tuning CORS policies
11  struct CORSRules
12  {
13  friend struct crow::CORSHandler;
14 
15  /// Set Access-Control-Allow-Origin. Default is "*"
16  CORSRules& origin(const std::string& origin)
17  {
18  origin_ = origin;
19  return *this;
20  }
21 
22  /// Set Access-Control-Allow-Methods. Default is "*"
23  CORSRules& methods(crow::HTTPMethod method)
24  {
25  add_list_item(methods_, crow::method_name(method));
26  return *this;
27  }
28 
29  /// Set Access-Control-Allow-Methods. Default is "*"
30  template<typename... Methods>
31  CORSRules& methods(crow::HTTPMethod method, Methods... method_list)
32  {
33  add_list_item(methods_, crow::method_name(method));
34  methods(method_list...);
35  return *this;
36  }
37 
38  /// Set Access-Control-Allow-Headers. Default is "*"
39  CORSRules& headers(const std::string& header)
40  {
41  add_list_item(headers_, header);
42  return *this;
43  }
44 
45  /// Set Access-Control-Allow-Headers. Default is "*"
46  template<typename... Headers>
47  CORSRules& headers(const std::string& header, Headers... header_list)
48  {
49  add_list_item(headers_, header);
50  headers(header_list...);
51  return *this;
52  }
53 
54  /// Set Access-Control-Max-Age. Default is none
56  {
57  max_age_ = std::to_string(max_age);
58  return *this;
59  }
60 
61  /// Enable Access-Control-Allow-Credentials
63  {
64  allow_credentials_ = true;
65  return *this;
66  }
67 
68  /// Ignore CORS and don't send any headers
69  void ignore()
70  {
71  ignore_ = true;
72  }
73 
74  /// Handle CORS on specific prefix path
75  CORSRules& prefix(const std::string& prefix);
76 
77  /// Handle CORS for specific blueprint
78  CORSRules& blueprint(const Blueprint& bp);
79 
80  /// Global CORS policy
81  CORSRules& global();
82 
83  private:
84  CORSRules() = delete;
85  CORSRules(CORSHandler* handler):
86  handler_(handler) {}
87 
88  /// build comma separated list
89  void add_list_item(std::string& list, const std::string& val)
90  {
91  if (list == "*") list = "";
92  if (list.size() > 0) list += ", ";
93  list += val;
94  }
95 
96  /// Set header `key` to `value` if it is not set
97  void set_header_no_override(const std::string& key, const std::string& value, crow::response& res)
98  {
99  if (value.size() == 0) return;
100  if (!get_header_value(res.headers, key).empty()) return;
101  res.add_header(key, value);
102  }
103 
104  /// Set response headers
105  void apply(crow::response& res)
106  {
107  if (ignore_) return;
108  set_header_no_override("Access-Control-Allow-Origin", origin_, res);
109  set_header_no_override("Access-Control-Allow-Methods", methods_, res);
110  set_header_no_override("Access-Control-Allow-Headers", headers_, res);
111  set_header_no_override("Access-Control-Max-Age", max_age_, res);
112  if (allow_credentials_) set_header_no_override("Access-Control-Allow-Credentials", "true", res);
113  }
114 
115  bool ignore_ = false;
116  // TODO: support multiple origins that are dynamically selected
117  std::string origin_ = "*";
118  std::string methods_ = "*";
119  std::string headers_ = "*";
120  std::string max_age_;
121  bool allow_credentials_ = false;
122 
123  CORSHandler* handler_;
124  };
125 
126  /// CORSHandler is a global middleware for setting CORS headers.
127 
128  ///
129  /// By default, it sets Access-Control-Allow-Origin/Methods/Headers to "*".
130  /// The default behaviour can be changed with the `global()` cors rule.
131  /// Additional rules for prexies can be added with `prefix()`.
132  struct CORSHandler
133  {
134  struct context
135  {};
136 
137  void before_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
138  {}
139 
140  void after_handle(crow::request& req, crow::response& res, context& /*ctx*/)
141  {
142  auto& rule = find_rule(req.url);
143  rule.apply(res);
144  }
145 
146  /// Handle CORS on a specific prefix path
147  CORSRules& prefix(const std::string& prefix)
148  {
149  rules.emplace_back(prefix, CORSRules(this));
150  return rules.back().second;
151  }
152 
153  /// Handle CORS for a specific blueprint
155  {
156  rules.emplace_back(bp.prefix(), CORSRules(this));
157  return rules.back().second;
158  }
159 
160  /// Get the global CORS policy
162  {
163  return default_;
164  }
165 
166  private:
167  CORSRules& find_rule(const std::string& path)
168  {
169  // TODO: use a trie in case of many rules
170  for (auto& rule : rules)
171  {
172  // Check if path starts with a rules prefix
173  if (path.rfind(rule.first, 0) == 0)
174  {
175  return rule.second;
176  }
177  }
178  return default_;
179  }
180 
181  std::vector<std::pair<std::string, CORSRules>> rules;
182  CORSRules default_ = CORSRules(this);
183  };
184 
185  inline CORSRules& CORSRules::prefix(const std::string& prefix)
186  {
187  return handler_->prefix(prefix);
188  }
189 
191  {
192  return handler_->blueprint(bp);
193  }
194 
196  {
197  return handler_->global();
198  }
199 
200 } // namespace crow
A blueprint can be considered a smaller section of a Crow app, specifically where the router is conec...
Definition: routing.h:1104
Definition: cors.h:135
CORSHandler is a global middleware for setting CORS headers.
Definition: cors.h:133
CORSRules & blueprint(const Blueprint &bp)
Handle CORS for a specific blueprint.
Definition: cors.h:154
CORSRules & prefix(const std::string &prefix)
Handle CORS on a specific prefix path.
Definition: cors.h:147
CORSRules & global()
Get the global CORS policy.
Definition: cors.h:161
Used for tuning CORS policies.
Definition: cors.h:12
CORSRules & global()
Global CORS policy.
Definition: cors.h:195
CORSRules & origin(const std::string &origin)
Set Access-Control-Allow-Origin. Default is "*".
Definition: cors.h:16
CORSRules & methods(crow::HTTPMethod method)
Set Access-Control-Allow-Methods. Default is "*".
Definition: cors.h:23
CORSRules & methods(crow::HTTPMethod method, Methods... method_list)
Set Access-Control-Allow-Methods. Default is "*".
Definition: cors.h:31
CORSRules & prefix(const std::string &prefix)
Handle CORS on specific prefix path.
Definition: cors.h:185
CORSRules & max_age(int max_age)
Set Access-Control-Max-Age. Default is none.
Definition: cors.h:55
CORSRules & allow_credentials()
Enable Access-Control-Allow-Credentials.
Definition: cors.h:62
CORSRules & blueprint(const Blueprint &bp)
Handle CORS for specific blueprint.
Definition: cors.h:190
CORSRules & headers(const std::string &header, Headers... header_list)
Set Access-Control-Allow-Headers. Default is "*".
Definition: cors.h:47
CORSRules & headers(const std::string &header)
Set Access-Control-Allow-Headers. Default is "*".
Definition: cors.h:39
void ignore()
Ignore CORS and don't send any headers.
Definition: cors.h:69
An HTTP request.
Definition: http_request.h:36
std::string url
The endpoint without any parameters.
Definition: http_request.h:39
HTTP response.
Definition: http_response.h:34
void add_header(std::string key, std::string value)
Add a new header to the response.
Definition: http_response.h:58
ci_map headers
HTTP headers.
Definition: http_response.h:42