From: Robin H. Johnson Date: Thu, 26 May 2016 22:41:20 +0000 (-0700) Subject: rgw: Fallback to Host header for bucket name. X-Git-Tag: v10.2.3~73^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=3ff6e8fa852346f4b69cd8c10b2f14ae4983d527;p=ceph.git rgw: Fallback to Host header for bucket name. RGW should fallback to using the Host header as the bucket name if valid & possible even when it is NOT a suffix match against the DNS names, or a match against the CNAME rule. This mirrors AWS S3 behavior for these cases (The AWS S3 does not do any DNS lookups regardless). Backport: jewel Fixes: http://tracker.ceph.com/issues/15975 Signed-off-by: Robin H. Johnson (cherry picked from commit 46aae19eeb91bf3ac78a94c9d4812a788d9042a8) --- diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 826c7a9d78b9a..034929b7b7c82 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -1596,6 +1596,27 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio) s->info.request_uri_aws4 = s->info.request_uri; s->cio = cio; + + // We need to know if this RGW instance is running the s3website API with a + // higher priority than regular S3 API, or possibly in place of the regular + // S3 API. + // Map the listing of rgw_enable_apis in REVERSE order, so that items near + // the front of the list have a higher number assigned (and -1 for items not in the list). + list apis; + get_str_list(g_conf->rgw_enable_apis, apis); + int api_priority_s3 = -1; + int api_priority_s3website = -1; + auto api_s3website_priority_rawpos = std::find(apis.begin(), apis.end(), "s3website"); + auto api_s3_priority_rawpos = std::find(apis.begin(), apis.end(), "s3"); + if (api_s3_priority_rawpos != apis.end()) { + api_priority_s3 = apis.size() - std::distance(apis.begin(), api_s3_priority_rawpos); + } + if (api_s3website_priority_rawpos != apis.end()) { + api_priority_s3website = apis.size() - std::distance(apis.begin(), api_s3website_priority_rawpos); + } + ldout(s->cct, 10) << "rgw api priority: s3=" << api_priority_s3 << " s3website=" << api_priority_s3website << dendl; + bool s3website_enabled = api_priority_s3website >= 0; + if (info.host.size()) { ldout(s->cct, 10) << "host=" << info.host << dendl; string domain; @@ -1603,7 +1624,6 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio) bool in_hosted_domain_s3website = false; bool in_hosted_domain = rgw_find_host_in_domains(info.host, &domain, &subdomain, hostnames_set); - bool s3website_enabled = g_conf->rgw_enable_apis.find("s3website") != std::string::npos; string s3website_domain; string s3website_subdomain; @@ -1613,7 +1633,6 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio) in_hosted_domain = true; // TODO: should hostnames be a strict superset of hostnames_s3website? domain = s3website_domain; subdomain = s3website_subdomain; - s->prot_flags |= RGW_REST_WEBSITE; } } @@ -1653,7 +1672,6 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio) // strict superset of hostnames_s3website? domain = s3website_domain; subdomain = s3website_subdomain; - s->prot_flags |= RGW_REST_WEBSITE; } } @@ -1666,6 +1684,31 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio) } } + // Handle A/CNAME records that point to the RGW storage, but do match the + // CNAME test above, per issue http://tracker.ceph.com/issues/15975 + // If BOTH domain & subdomain variables are empty, then none of the above + // cases matched anything, and we should fall back to using the Host header + // directly as the bucket name. + // As additional checks: + // - if the Host header is an IP, we're using path-style access without DNS + // - Also check that the Host header is a valid bucket name before using it. + if (subdomain.empty() + && (domain.empty() || domain != info.host) + && !looks_like_ip_address(info.host.c_str()) + && RGWHandler_REST::validate_bucket_name(info.host)) { + subdomain.append(info.host); + in_hosted_domain = 1; + } + + if (s3website_enabled && api_priority_s3website > api_priority_s3) { + in_hosted_domain_s3website = 1; + } + + if (in_hosted_domain_s3website) { + s->prot_flags |= RGW_REST_WEBSITE; + } + + if (in_hosted_domain && !subdomain.empty()) { string encoded_bucket = "/"; encoded_bucket.append(subdomain); @@ -1678,6 +1721,16 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO* cio) if (!domain.empty()) { s->info.domain = domain; } + + ldout(s->cct, 20) + << "final domain/bucket" + << " subdomain=" << subdomain + << " domain=" << domain + << " in_hosted_domain=" << in_hosted_domain + << " in_hosted_domain_s3website=" << in_hosted_domain_s3website + << " s->info.domain=" << s->info.domain + << " s->info.request_uri=" << s->info.request_uri + << dendl; } if (s->info.domain.empty()) { diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index b3568cf5794ed..fe6a6f553bd76 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -377,16 +377,16 @@ protected: virtual RGWOp *op_copy() { return NULL; } virtual RGWOp *op_options() { return NULL; } - virtual int validate_tenant_name(const string& bucket); - virtual int validate_bucket_name(const string& bucket); - virtual int validate_object_name(const string& object); - static int allocate_formatter(struct req_state *s, int default_formatter, bool configurable); public: RGWHandler_REST() {} virtual ~RGWHandler_REST() {} + static int validate_tenant_name(const string& bucket); + static int validate_bucket_name(const string& bucket); + static int validate_object_name(const string& object); + int init_permissions(RGWOp* op); int read_permissions(RGWOp* op); diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index 1482a95287f00..f14c01cd1fee0 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -445,11 +445,8 @@ public: RGWHandler_Auth_S3() : RGWHandler_REST() {} virtual ~RGWHandler_Auth_S3() {} - virtual int validate_bucket_name(const string& bucket) { - return 0; - } - - virtual int validate_object_name(const string& bucket) { return 0; } + static int validate_bucket_name(const string& bucket); + static int validate_object_name(const string& bucket); virtual int init(RGWRados *store, struct req_state *s, RGWClientIO *cio); virtual int authorize() { diff --git a/src/rgw/rgw_rest_swift.h b/src/rgw/rgw_rest_swift.h index bbef15bf9b495..0c4b1e25100cb 100644 --- a/src/rgw/rgw_rest_swift.h +++ b/src/rgw/rgw_rest_swift.h @@ -197,7 +197,7 @@ public: RGWHandler_REST_SWIFT() {} virtual ~RGWHandler_REST_SWIFT() {} - int validate_bucket_name(const string& bucket); + static int validate_bucket_name(const string& bucket); int init(RGWRados *store, struct req_state *s, RGWClientIO *cio); int authorize();