diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index d98d7f9fd85..655bbd290e5 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -1671,6 +1671,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; @@ -1678,7 +1699,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; @@ -1688,7 +1708,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; } } @@ -1728,7 +1747,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; } } @@ -1741,6 +1759,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); @@ -1753,6 +1796,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 65659d3b49e..3e23945fb2d 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -380,16 +380,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 ab9110f4e6f..cecc14c9765 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -452,11 +452,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 bbef15bf9b4..0c4b1e25100 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();