diff --git a/autotest/gcore/vsis3.py b/autotest/gcore/vsis3.py
index 8cec895db836..d4a94b6cb027 100755
--- a/autotest/gcore/vsis3.py
+++ b/autotest/gcore/vsis3.py
@@ -988,6 +988,43 @@ def method_req_2(self, request):
###############################################################################
+@gdaltest.enable_exceptions()
+def test_vsis3_permanent_redirect_and_region_change(aws_test_config, webserver_port):
+
+ handler = webserver.SequentialHandler()
+ handler.add(
+ "GET",
+ "/test_vsis3_permanent_redirect_and_region_change/?delimiter=%2F&list-type=2",
+ 301,
+ {"Content-type": "application/xml"},
+ f"""
+ PermanentRedirectThe bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.localhost:{webserver_port}test_vsis3_permanent_redirect_and_region_change""",
+ )
+ handler.add(
+ "GET",
+ "/test_vsis3_permanent_redirect_and_region_change/?delimiter=%2F&list-type=2",
+ 200,
+ {"Content-type": "application/xml"},
+ """
+
+
+
+ test.bin
+ 1970-01-01T00:00:01.000Z
+ 123456
+
+ """,
+ )
+ with webserver.install_http_handler(handler):
+ with gdal.VSIFile(
+ "/vsis3/test_vsis3_permanent_redirect_and_region_change/test.bin", "rb"
+ ):
+ pass
+
+
+###############################################################################
+
+
@pytest.mark.parametrize("with_error_message", [True, False])
def test_vsis3_request_timeout(aws_test_config, webserver_port, with_error_message):
gdal.VSICurlClearCache()
diff --git a/port/cpl_aws.cpp b/port/cpl_aws.cpp
index ac4aabe69443..63017884f216 100644
--- a/port/cpl_aws.cpp
+++ b/port/cpl_aws.cpp
@@ -2809,48 +2809,54 @@ bool VSIS3HandleHelper::CanRestartOnError(const char *pszErrorMsg,
}
return false;
}
- if (!m_bUseVirtualHosting &&
- strncmp(pszEndpoint, m_osBucket.c_str(), m_osBucket.size()) == 0 &&
- pszEndpoint[m_osBucket.size()] == '.')
+
+ /* If we have a body with
+ PermanentRedirectThe bucket you are
+ attempting to access must be addressed using the specified endpoint.
+ Please send all future requests to this
+ endpoint.bucketbucket.region.s3.amazonaws.com
+ and headers like
+ x-amz-bucket-region: eu-west-1
+ then we must use s3-$(x-amz-bucket-region).amazon.com as endpoint. */
+ const char *pszRegionPtr =
+ (pszHeaders != nullptr)
+ ? strstr(pszHeaders, "x-amz-bucket-region: ")
+ : nullptr;
+ if (pszRegionPtr != nullptr)
{
- /* If we have a body with
- PermanentRedirectThe bucket you are
- attempting to access must be addressed using the specified endpoint.
- Please send all future requests to this
- endpoint.bucket.with.dotbucket.with.dot.s3.amazonaws.com
- and headers like
- x-amz-bucket-region: eu-west-1
- and the bucket name has dot in it,
- then we must use s3.$(x-amz-bucket-region).amazon.com as endpoint.
- See #7154 */
- const char *pszRegionPtr =
- (pszHeaders != nullptr)
- ? strstr(pszHeaders, "x-amz-bucket-region: ")
- : nullptr;
- if (strchr(m_osBucket.c_str(), '.') != nullptr &&
- pszRegionPtr != nullptr)
+ std::string osRegion(pszRegionPtr +
+ strlen("x-amz-bucket-region: "));
+ size_t nPos = osRegion.find('\r');
+ if (nPos != std::string::npos)
+ osRegion.resize(nPos);
+ if (strncmp(pszEndpoint, m_osBucket.c_str(), m_osBucket.size()) ==
+ 0 &&
+ pszEndpoint[m_osBucket.size()] == '.')
{
- std::string osRegion(pszRegionPtr +
- strlen("x-amz-bucket-region: "));
- size_t nPos = osRegion.find('\r');
- if (nPos != std::string::npos)
- osRegion.resize(nPos);
- SetEndpoint(
- CPLSPrintf("s3.%s.amazonaws.com", osRegion.c_str()));
- SetRegion(osRegion.c_str());
- CPLDebug(AWS_DEBUG_KEY, "Switching to endpoint %s",
- m_osEndpoint.c_str());
- CPLDebug(AWS_DEBUG_KEY, "Switching to region %s",
- m_osRegion.c_str());
- CPLDestroyXMLNode(psTree);
- if (!bIsTemporaryRedirect)
- VSIS3UpdateParams::UpdateMapFromHandle(this);
- return true;
+ pszEndpoint += m_osBucket.size() + 1;
}
+ SetEndpoint(pszEndpoint);
+ SetRegion(osRegion.c_str());
+ CPLDebug(AWS_DEBUG_KEY, "Switching to endpoint %s",
+ m_osEndpoint.c_str());
+ CPLDebug(AWS_DEBUG_KEY, "Switching to region %s",
+ m_osRegion.c_str());
+ CPLDestroyXMLNode(psTree);
+ if (!bIsTemporaryRedirect)
+ VSIS3UpdateParams::UpdateMapFromHandle(this);
+ return true;
+ }
+
+ if (!m_bUseVirtualHosting &&
+ m_osBucket.find('.') == std::string::npos &&
+ strncmp(pszEndpoint, m_osBucket.c_str(), m_osBucket.size()) == 0 &&
+ pszEndpoint[m_osBucket.size()] == '.')
+ {
m_bUseVirtualHosting = true;
CPLDebug(AWS_DEBUG_KEY, "Switching to virtual hosting");
}
+
SetEndpoint(m_bUseVirtualHosting ? pszEndpoint + m_osBucket.size() + 1
: pszEndpoint);
CPLDebug(AWS_DEBUG_KEY, "Switching to endpoint %s",