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