summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehuda Sadeh <yehuda@inktank.com>2013-08-22 10:00:53 -0700
committerYehuda Sadeh <yehuda@inktank.com>2013-09-11 09:45:14 -0700
commit94e7b594d85dbd26e58d823b41f418032e9f163f (patch)
treefa9e65e6d18e781ec01e028dcbaa1d10125d0ce4
parentc3385d8a102faf5379559bb98cf89637ceda1579 (diff)
downloadceph-94e7b594d85dbd26e58d823b41f418032e9f163f.tar.gz
rgw: add a generic CORS response handling
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r--src/rgw/rgw_op.cc189
-rw-r--r--src/rgw/rgw_op.h7
-rw-r--r--src/rgw/rgw_rest.cc14
-rw-r--r--src/rgw/rgw_rest.h1
-rw-r--r--src/rgw/rgw_rest_s3.cc2
5 files changed, 138 insertions, 75 deletions
diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc
index 1dfdc9dc37e..523fbdae9b2 100644
--- a/src/rgw/rgw_op.cc
+++ b/src/rgw/rgw_op.cc
@@ -421,6 +421,107 @@ int RGWOp::verify_op_mask()
return 0;
}
+static bool validate_cors_rule_method(RGWCORSRule *rule, const char *req_meth) {
+ uint8_t flags = 0;
+ if (strcmp(req_meth, "GET") == 0) flags = RGW_CORS_GET;
+ else if (strcmp(req_meth, "POST") == 0) flags = RGW_CORS_POST;
+ else if (strcmp(req_meth, "PUT") == 0) flags = RGW_CORS_PUT;
+ else if (strcmp(req_meth, "DELETE") == 0) flags = RGW_CORS_DELETE;
+ else if (strcmp(req_meth, "HEAD") == 0) flags = RGW_CORS_HEAD;
+
+ if ((rule->get_allowed_methods() & flags) == flags) {
+ dout(10) << "Method " << req_meth << " is supported" << dendl;
+ } else {
+ dout(5) << "Method " << req_meth << " is not supported" << dendl;
+ return false;
+ }
+
+ return true;
+}
+
+int RGWOp::read_bucket_cors()
+{
+ bufferlist bl;
+
+ map<string, bufferlist>::iterator aiter = s->bucket_attrs.find(RGW_ATTR_CORS);
+ if (aiter == s->bucket_attrs.end()) {
+ ldout(s->cct, 20) << "no CORS configuration attr found" << dendl;
+ cors_exist = false;
+ return 0; /* no CORS configuration found */
+ }
+
+ cors_exist = true;
+
+ bl = aiter->second;
+
+ bufferlist::iterator iter = bl.begin();
+ try {
+ bucket_cors.decode(iter);
+ } catch (buffer::error& err) {
+ ldout(s->cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl;
+ return -EIO;
+ }
+ if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) {
+ RGWCORSConfiguration_S3 *s3cors = static_cast<RGWCORSConfiguration_S3 *>(&bucket_cors);
+ ldout(s->cct, 15) << "Read RGWCORSConfiguration";
+ s3cors->to_xml(*_dout);
+ *_dout << dendl;
+ }
+ return 0;
+}
+
+static void get_cors_response_headers(RGWCORSRule *rule, const char *req_hdrs, string& hdrs, string& exp_hdrs, unsigned *max_age) {
+ if (req_hdrs) {
+ list<string> hl;
+ get_str_list(req_hdrs, hl);
+ for(list<string>::iterator it = hl.begin(); it != hl.end(); ++it) {
+ if (!rule->is_header_allowed((*it).c_str(), (*it).length())) {
+ dout(5) << "Header " << (*it) << " is not registered in this rule" << dendl;
+ } else {
+ if (hdrs.length() > 0) hdrs.append(",");
+ hdrs.append((*it));
+ }
+ }
+ }
+ rule->format_exp_headers(exp_hdrs);
+ *max_age = rule->get_max_age();
+}
+
+bool RGWOp::generate_cors_headers(string& origin, string& method, string& headers, string& exp_headers, unsigned *max_age)
+{
+ const char *orig = s->info.env->get("HTTP_ORIGIN");
+ if (!orig) {
+ return false;
+ }
+ origin = orig;
+ int ret = read_bucket_cors();
+ if (ret < 0) {
+ return false;
+ }
+
+ if (!cors_exist) {
+ dout(2) << "No CORS configuration set yet for this bucket" << dendl;
+ return false;
+ }
+ const char *req_meth = s->info.env->get("HTTP_ACCESS_CONTROL_REQUEST_METHOD");
+ if (!req_meth) {
+ req_meth = s->info.method;
+ }
+
+ if (req_meth)
+ method = req_meth;
+
+ RGWCORSRule *rule = bucket_cors.host_name_rule(orig);
+ if (!validate_cors_rule_method(rule, req_meth)) {
+ return false;
+ }
+
+ const char *req_hdrs = s->info.env->get("HTTP_ACCESS_CONTROL_ALLOW_HEADERS");
+
+ get_cors_response_headers(rule, req_hdrs, headers, exp_headers, max_age);
+
+ return true;
+}
int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket, RGWObjEnt& ent, RGWAccessControlPolicy *bucket_policy, off_t start_ofs, off_t end_ofs)
{
@@ -1835,37 +1936,6 @@ void RGWPutACLs::execute()
}
}
-static int read_bucket_cors(RGWRados *store, struct req_state *s, RGWCORSConfiguration *bucket_cors, bool *exist)
-{
- bufferlist bl;
-
- map<string, bufferlist>::iterator aiter = s->bucket_attrs.find(RGW_ATTR_CORS);
- if (aiter == s->bucket_attrs.end()) {
- ldout(s->cct, 20) << "no CORS configuration attr found" << dendl;
- *exist = false;
- return 0; /* no CORS configuration found */
- }
-
- *exist = true;
-
- bl = aiter->second;
-
- bufferlist::iterator iter = bl.begin();
- try {
- bucket_cors->decode(iter);
- } catch (buffer::error& err) {
- ldout(s->cct, 0) << "ERROR: could not decode policy, caught buffer::error" << dendl;
- return -EIO;
- }
- if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 15)) {
- RGWCORSConfiguration_S3 *s3cors = static_cast<RGWCORSConfiguration_S3 *>(bucket_cors);
- ldout(s->cct, 15) << "Read RGWCORSConfiguration";
- s3cors->to_xml(*_dout);
- *_dout << dendl;
- }
- return 0;
-}
-
int RGWGetCORS::verify_permission()
{
if (s->user.user_id.compare(s->bucket_owner.get_id()) != 0)
@@ -1876,9 +1946,7 @@ int RGWGetCORS::verify_permission()
void RGWGetCORS::execute()
{
- bool cors_exist;
-
- ret = read_bucket_cors(store, s, &bucket_cors, &cors_exist);
+ ret = read_bucket_cors();
if (ret < 0)
return ;
@@ -1922,9 +1990,8 @@ int RGWDeleteCORS::verify_permission()
void RGWDeleteCORS::execute()
{
- bool cors_exist;
RGWCORSConfiguration bucket_cors;
- ret = read_bucket_cors(store, s, &bucket_cors, &cors_exist);
+ ret = read_bucket_cors();
if (ret < 0)
return;
@@ -1961,41 +2028,17 @@ void RGWDeleteCORS::execute()
}
void RGWOptionsCORS::get_response_params(string& hdrs, string& exp_hdrs, unsigned *max_age) {
- if (req_hdrs) {
- list<string> hl;
- get_str_list(req_hdrs, hl);
- for(list<string>::iterator it = hl.begin(); it != hl.end(); ++it) {
- if (!rule->is_header_allowed((*it).c_str(), (*it).length())) {
- dout(5) << "Header " << (*it) << " is not registered in this rule" << dendl;
- } else {
- if (hdrs.length() > 0)hdrs.append(",");
- hdrs.append((*it));
- }
- }
- }
- rule->format_exp_headers(exp_hdrs);
- *max_age = rule->get_max_age();
+ get_cors_response_headers(rule, req_hdrs, hdrs, exp_hdrs, max_age);
}
int RGWOptionsCORS::validate_cors_request(RGWCORSConfiguration *cc) {
rule = cc->host_name_rule(origin);
if (!rule) {
- dout(10) << "There is no corsrule present for " << origin << dendl;
+ dout(10) << "There is no cors rule present for " << origin << dendl;
return -ENOENT;
}
- uint8_t flags = 0;
- if (strcmp(req_meth, "GET") == 0) flags = RGW_CORS_GET;
- else if (strcmp(req_meth, "POST") == 0) flags = RGW_CORS_POST;
- else if (strcmp(req_meth, "PUT") == 0) flags = RGW_CORS_PUT;
- else if (strcmp(req_meth, "DELETE") == 0) flags = RGW_CORS_DELETE;
- else if (strcmp(req_meth, "HEAD") == 0) flags = RGW_CORS_HEAD;
-
- if ((rule->get_allowed_methods() & flags) == flags) {
- dout(10) << "Method " << req_meth << " is supported" << dendl;
- } else {
- dout(5) << "Method " << req_meth << " is not supported" << dendl;
- req_meth = NULL;
+ if (!validate_cors_rule_method(rule, req_meth)) {
return -ENOTSUP;
}
return 0;
@@ -2003,12 +2046,18 @@ int RGWOptionsCORS::validate_cors_request(RGWCORSConfiguration *cc) {
void RGWOptionsCORS::execute()
{
- RGWCORSConfiguration bucket_cors;
- bool cors_exist;
- ret = read_bucket_cors(store, s, &bucket_cors, &cors_exist);
+ ret = read_bucket_cors();
if (ret < 0)
return;
+ origin = s->info.env->get("HTTP_ORIGIN");
+ if (!origin) {
+ dout(0) <<
+ "Preflight request without mandatory Origin header"
+ << dendl;
+ ret = -EACCES;
+ return;
+ }
if (!cors_exist) {
dout(2) << "No CORS configuration set yet for this bucket" << dendl;
ret = -ENOENT;
@@ -2022,14 +2071,6 @@ void RGWOptionsCORS::execute()
ret = -EACCES;
return;
}
- origin = s->info.env->get("HTTP_ORIGIN");
- if (!origin) {
- dout(0) <<
- "Preflight request without mandatory Origin header"
- << dendl;
- ret = -EACCES;
- return;
- }
req_hdrs = s->info.env->get("HTTP_ACCESS_CONTROL_ALLOW_HEADERS");
ret = validate_cors_request(&bucket_cors);
if (!rule) {
diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h
index 4091ad42038..241584bac68 100644
--- a/src/rgw/rgw_op.h
+++ b/src/rgw/rgw_op.h
@@ -34,8 +34,10 @@ protected:
struct req_state *s;
RGWHandler *dialect_handler;
RGWRados *store;
+ RGWCORSConfiguration bucket_cors;
+ bool cors_exist;
public:
- RGWOp() : s(NULL), dialect_handler(NULL), store(NULL) {}
+ RGWOp() : s(NULL), dialect_handler(NULL), store(NULL), cors_exist(false) {}
virtual ~RGWOp() {}
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *dialect_handler) {
@@ -43,6 +45,9 @@ public:
this->s = s;
this->dialect_handler = dialect_handler;
}
+ int read_bucket_cors();
+ bool generate_cors_headers(string& origin, string& method, string& headers, string& exp_headers, unsigned *max_age);
+
virtual int verify_params() { return 0; }
virtual bool prefetch_data() { return false; }
virtual int verify_permission() = 0;
diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc
index 05d67fbeeff..87aead0b250 100644
--- a/src/rgw/rgw_rest.cc
+++ b/src/rgw/rgw_rest.cc
@@ -377,6 +377,20 @@ void dump_access_control(struct req_state *s, const char *origin, const char *me
}
}
+void dump_access_control(req_state *s, RGWOp *op)
+{
+ string origin;
+ string method;
+ string header;
+ string exp_header;
+ unsigned max_age = CORS_MAX_AGE_INVALID;
+
+ if (!op->generate_cors_headers(origin, method, header, exp_header, &max_age))
+ return;
+
+ dump_access_control(s, origin.c_str(), method.c_str(), header.c_str(), exp_header.c_str(), max_age);
+}
+
void dump_start(struct req_state *s)
{
if (!s->content_started) {
diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h
index b65efb3de3e..12fcf783687 100644
--- a/src/rgw/rgw_rest.h
+++ b/src/rgw/rgw_rest.h
@@ -331,6 +331,7 @@ extern void dump_pair(struct req_state *s, const char *key, const char *value);
extern bool is_valid_url(const char *url);
extern void dump_access_control(struct req_state *s, const char *origin, const char *meth,
const char *hdr, const char *exp_hdr, uint32_t max_age);
+extern void dump_access_control(req_state *s, RGWOp *op);
#endif
diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc
index ab6e6644297..9e27c37e448 100644
--- a/src/rgw/rgw_rest_s3.cc
+++ b/src/rgw/rgw_rest_s3.cc
@@ -166,6 +166,8 @@ done:
if (!content_type)
content_type = "binary/octet-stream";
+
+ dump_access_control(s, this);
end_header(s, content_type);
if (metadata_bl.length()) {