]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_cors.cc
422767f34eb22101a512b041aa83471016581212
[ceph.git] / ceph / src / rgw / rgw_cors.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 /*
5 * Ceph - scalable distributed file system
6 *
7 * Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
15
16 #include <string.h>
17
18 #include <iostream>
19 #include <map>
20
21 #include <boost/algorithm/string.hpp>
22
23 #include "include/types.h"
24 #include "common/debug.h"
25 #include "include/str_list.h"
26 #include "common/Formatter.h"
27
28 #include "rgw_cors.h"
29
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_rgw
32
33 void RGWCORSRule::dump_origins() {
34 unsigned num_origins = allowed_origins.size();
35 dout(10) << "Allowed origins : " << num_origins << dendl;
36 for(set<string>::iterator it = allowed_origins.begin();
37 it != allowed_origins.end();
38 ++it) {
39 dout(10) << *it << "," << dendl;
40 }
41 }
42
43 void RGWCORSRule::erase_origin_if_present(string& origin, bool *rule_empty) {
44 set<string>::iterator it = allowed_origins.find(origin);
45 if (!rule_empty)
46 return;
47 *rule_empty = false;
48 if (it != allowed_origins.end()) {
49 dout(10) << "Found origin " << origin << ", set size:" <<
50 allowed_origins.size() << dendl;
51 allowed_origins.erase(it);
52 *rule_empty = (allowed_origins.empty());
53 }
54 }
55
56 /*
57 * make attrs look-like-this
58 * does not convert underscores or dashes
59 *
60 * Per CORS specification, section 3:
61 * ===
62 * "Converting a string to ASCII lowercase" means replacing all characters in the
63 * range U+0041 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z with
64 * the corresponding characters in the range U+0061 LATIN SMALL LETTER A to
65 * U+007A LATIN SMALL LETTER Z).
66 * ===
67 *
68 * @todo When UTF-8 is allowed in HTTP headers, this function will need to change
69 */
70 string lowercase_http_attr(const string& orig)
71 {
72 const char *s = orig.c_str();
73 char buf[orig.size() + 1];
74 buf[orig.size()] = '\0';
75
76 for (size_t i = 0; i < orig.size(); ++i, ++s) {
77 buf[i] = tolower(*s);
78 }
79 return string(buf);
80 }
81
82
83 static bool is_string_in_set(set<string>& s, string h) {
84 if ((s.find("*") != s.end()) ||
85 (s.find(h) != s.end())) {
86 return true;
87 }
88 /* The header can be Content-*-type, or Content-* */
89 for(set<string>::iterator it = s.begin();
90 it != s.end(); ++it) {
91 size_t off;
92 if ((off = (*it).find("*"))!=string::npos) {
93 list<string> ssplit;
94 unsigned flen = 0;
95
96 get_str_list((*it), "* \t", ssplit);
97 if (off != 0) {
98 string sl = ssplit.front();
99 flen = sl.length();
100 dout(10) << "Finding " << sl << ", in " << h << ", at offset 0" << dendl;
101 if (!boost::algorithm::starts_with(h,sl))
102 continue;
103 ssplit.pop_front();
104 }
105 if (off != ((*it).length() - 1)) {
106 string sl = ssplit.front();
107 dout(10) << "Finding " << sl << ", in " << h
108 << ", at offset not less than " << flen << dendl;
109 if (h.size() < sl.size() ||
110 h.compare((h.size() - sl.size()), sl.size(), sl) != 0)
111 continue;
112 ssplit.pop_front();
113 }
114 if (!ssplit.empty())
115 continue;
116 return true;
117 }
118 }
119 return false;
120 }
121
122 bool RGWCORSRule::has_wildcard_origin() {
123 if (allowed_origins.find("*") != allowed_origins.end())
124 return true;
125
126 return false;
127 }
128
129 bool RGWCORSRule::is_origin_present(const char *o) {
130 string origin = o;
131 return is_string_in_set(allowed_origins, origin);
132 }
133
134 bool RGWCORSRule::is_header_allowed(const char *h, size_t len) {
135 string hdr(h, len);
136 if(lowercase_allowed_hdrs.empty()) {
137 set<string>::iterator iter;
138 for (iter = allowed_hdrs.begin(); iter != allowed_hdrs.end(); ++iter) {
139 lowercase_allowed_hdrs.insert(lowercase_http_attr(*iter));
140 }
141 }
142 return is_string_in_set(lowercase_allowed_hdrs, lowercase_http_attr(hdr));
143 }
144
145 void RGWCORSRule::format_exp_headers(string& s) {
146 s = "";
147 for(list<string>::iterator it = exposable_hdrs.begin();
148 it != exposable_hdrs.end(); ++it) {
149 if (s.length() > 0)
150 s.append(",");
151 s.append((*it));
152 }
153 }
154
155 RGWCORSRule * RGWCORSConfiguration::host_name_rule(const char *origin) {
156 for(list<RGWCORSRule>::iterator it_r = rules.begin();
157 it_r != rules.end(); ++it_r) {
158 RGWCORSRule& r = (*it_r);
159 if (r.is_origin_present(origin))
160 return &r;
161 }
162 return NULL;
163 }
164
165 void RGWCORSConfiguration::erase_host_name_rule(string& origin) {
166 bool rule_empty;
167 unsigned loop = 0;
168 /*Erase the host name from that rule*/
169 dout(10) << "Num of rules : " << rules.size() << dendl;
170 for(list<RGWCORSRule>::iterator it_r = rules.begin();
171 it_r != rules.end(); ++it_r, loop++) {
172 RGWCORSRule& r = (*it_r);
173 r.erase_origin_if_present(origin, &rule_empty);
174 dout(10) << "Origin:" << origin << ", rule num:"
175 << loop << ", emptying now:" << rule_empty << dendl;
176 if (rule_empty) {
177 rules.erase(it_r);
178 break;
179 }
180 }
181 }
182
183 void RGWCORSConfiguration::dump() {
184 unsigned loop = 1;
185 unsigned num_rules = rules.size();
186 dout(10) << "Number of rules: " << num_rules << dendl;
187 for(list<RGWCORSRule>::iterator it = rules.begin();
188 it!= rules.end(); ++it, loop++) {
189 dout(10) << " <<<<<<< Rule " << loop << " >>>>>>> " << dendl;
190 (*it).dump_origins();
191 }
192 }