]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rgw/s3: apply vhost logic to s3 only
authorCasey Bodley <cbodley@redhat.com>
Thu, 3 Jul 2025 16:01:18 +0000 (12:01 -0400)
committerCasey Bodley <cbodley@redhat.com>
Tue, 21 Oct 2025 15:42:25 +0000 (11:42 -0400)
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 <cbodley@redhat.com>
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_rest_s3.cc

index e51cb5694e74ec3b6dae73bd5d70cd14e81eba96..4db82c7dd8cf36bc7581084d5015425e017d1cac 100644 (file)
@@ -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
    * ===
index 7b540a494e616991958def91f211ecce1b7a197e..1de2ba1b2f58bdebc71ca0dfdaa94ea675a46d51 100644 (file)
@@ -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,
index fd5b584fb80f5a67dab9dd37d4c4bedd73b6a193..44db27c5ffc556e039d1446f39b361d51bb3500f 100644 (file)
@@ -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,