From: Casey Bodley Date: Thu, 3 Jul 2025 16:01:18 +0000 (-0400) Subject: rgw/s3: apply vhost logic to s3 only X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=806be3347ebf552bc75ff8cb1b8cf8cf29ed139d;p=ceph-ci.git rgw/s3: apply vhost logic to s3 only the vhost-style transformations ran in RGWREST::preprocess() before we even route the request, so applied to every REST API in radosgw vhost-style requests are specific to the S3 API, so they should only apply after being routed to RGWRESTMgr_S3 extract the vhost logic from RGWREST::proprocess() into rgw_rest_transform_s3_vhost_style(), and call that only from RGWRESTMgr_S3::get_resource_mgr_as_default() url-decoding of request_uri into decoded_uri is now duplicated in preprocess() to apply to all requests, then again after vhost-style transforms the request_uri Signed-off-by: Casey Bodley --- diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index e51cb5694e7..4db82c7dd8c 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -2030,17 +2030,8 @@ RGWRESTMgr::~RGWRESTMgr() delete default_mgr; } -int RGWREST::preprocess(req_state *s, rgw::io::BasicClient* cio) +int rgw_rest_transform_s3_vhost_style(req_state* s) { - req_info& info = s->info; - - /* save the request uri used to hash on the client side. request_uri may suffer - modifications as part of the bucket encoding in the subdomain calling format. - request_uri_aws4 will be used under aws4 auth */ - 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. @@ -2060,6 +2051,7 @@ int RGWREST::preprocess(req_state *s, rgw::io::BasicClient* cio) ldpp_dout(s, 10) << "rgw api priority: s3=" << api_priority_s3 << " s3website=" << api_priority_s3website << dendl; bool s3website_enabled = api_priority_s3website >= 0; + req_info& info = s->info; if (info.host.size()) { ssize_t pos; if (info.host.find('[') == 0) { @@ -2205,6 +2197,26 @@ int RGWREST::preprocess(req_state *s, rgw::io::BasicClient* cio) return -ERR_ZERO_IN_URL; } + return 0; +} + +int RGWREST::preprocess(req_state *s, rgw::io::BasicClient* cio) +{ + req_info& info = s->info; + + /* save the request uri used to hash on the client side. request_uri may suffer + modifications as part of the bucket encoding in the subdomain calling format. + request_uri_aws4 will be used under aws4 auth */ + s->info.request_uri_aws4 = s->info.request_uri; + + s->cio = cio; + + s->decoded_uri = url_decode(s->info.request_uri); + /* Validate for being free of the '\0' buried in the middle of the string. */ + if (std::strlen(s->decoded_uri.c_str()) != s->decoded_uri.length()) { + return -ERR_ZERO_IN_URL; + } + /* FastCGI specification, section 6.3 * http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S6.3 * === diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index 7b540a494e6..1de2ba1b2f5 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -835,6 +835,12 @@ inline std::string compute_domain_uri(const req_state *s) { return uri; } +// Transform S3 virtual-host style requests to a path-style request. +// When the Host header includes the bucket name as a subdomain, prepend +// that bucket name to s->info.request_uri then re-url-decode that +// into s->decoded_uri. +int rgw_rest_transform_s3_vhost_style(req_state* s); + extern void dump_content_length(req_state *s, uint64_t len); extern void dump_etag(req_state *s, const std::string_view& etag, diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index fd5b584fb80..44db27c5ffc 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -5986,13 +5986,23 @@ RGWRESTMgr* RGWRESTMgr_S3::get_resource_mgr_as_default(req_state* s, const std::string& uri, std::string* out_uri) { + // check the Host header for virtual-host style requests, and + // rewrite the request_uri with the subdomain as the bucket name. + // this applies to s3 and s3website requests, but not s3control + int ret = rgw_rest_transform_s3_vhost_style(s); + if (ret < 0) { + return nullptr; + } + // use the updated decoded_uri for routing + const std::string& new_uri = s->decoded_uri; + // route matching requests to RGWRESTMgr_S3Website const bool in_s3website_domain = (s->prot_flags & RGW_REST_WEBSITE); if (s3website && in_s3website_domain) { - return s3website->get_resource_mgr(s, uri, out_uri); + return s3website->get_resource_mgr(s, new_uri, out_uri); } - return RGWRESTMgr::get_resource_mgr(s, uri, out_uri); + return RGWRESTMgr::get_resource_mgr(s, new_uri, out_uri); } RGWHandler_REST* RGWRESTMgr_S3::get_handler(rgw::sal::Driver* driver,