Skip to content

Commit 4c2d1bb

Browse files
committed
/vsis3/: support changing region and endpoint in a single operation, for virtual hosting as well
Previously this optimization was limited only to non virtual hosting scenarios. An for virtual hosting, we did first the endpoint change and then the region change.
1 parent 06444a6 commit 4c2d1bb

2 files changed

Lines changed: 78 additions & 35 deletions

File tree

autotest/gcore/vsis3.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,43 @@ def method_req_2(self, request):
988988
###############################################################################
989989

990990

991+
@gdaltest.enable_exceptions()
992+
def test_vsis3_permanent_redirect_and_region_change(aws_test_config, webserver_port):
993+
994+
handler = webserver.SequentialHandler()
995+
handler.add(
996+
"GET",
997+
"/test_vsis3_permanent_redirect_and_region_change/?delimiter=%2F&list-type=2",
998+
301,
999+
{"Content-type": "application/xml"},
1000+
f"""<?xml version="1.0" encoding="UTF-8"?>
1001+
<Error><Code>PermanentRedirect</Code><Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message><Endpoint>localhost:{webserver_port}</Endpoint><Bucket>test_vsis3_permanent_redirect_and_region_change</Bucket></Error>""",
1002+
)
1003+
handler.add(
1004+
"GET",
1005+
"/test_vsis3_permanent_redirect_and_region_change/?delimiter=%2F&list-type=2",
1006+
200,
1007+
{"Content-type": "application/xml"},
1008+
"""<?xml version="1.0" encoding="UTF-8"?>
1009+
<ListBucketResult>
1010+
<Prefix></Prefix>
1011+
<Contents>
1012+
<Key>test.bin</Key>
1013+
<LastModified>1970-01-01T00:00:01.000Z</LastModified>
1014+
<Size>123456</Size>
1015+
</Contents>
1016+
</ListBucketResult>""",
1017+
)
1018+
with webserver.install_http_handler(handler):
1019+
with gdal.VSIFile(
1020+
"/vsis3/test_vsis3_permanent_redirect_and_region_change/test.bin", "rb"
1021+
):
1022+
pass
1023+
1024+
1025+
###############################################################################
1026+
1027+
9911028
@pytest.mark.parametrize("with_error_message", [True, False])
9921029
def test_vsis3_request_timeout(aws_test_config, webserver_port, with_error_message):
9931030
gdal.VSICurlClearCache()

port/cpl_aws.cpp

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2809,48 +2809,54 @@ bool VSIS3HandleHelper::CanRestartOnError(const char *pszErrorMsg,
28092809
}
28102810
return false;
28112811
}
2812-
if (!m_bUseVirtualHosting &&
2813-
strncmp(pszEndpoint, m_osBucket.c_str(), m_osBucket.size()) == 0 &&
2814-
pszEndpoint[m_osBucket.size()] == '.')
2812+
2813+
/* If we have a body with
2814+
<Error><Code>PermanentRedirect</Code><Message>The bucket you are
2815+
attempting to access must be addressed using the specified endpoint.
2816+
Please send all future requests to this
2817+
endpoint.</Message><Bucket>bucket</Bucket><Endpoint>bucket.region.s3.amazonaws.com</Endpoint></Error>
2818+
and headers like
2819+
x-amz-bucket-region: eu-west-1
2820+
then we must use s3-$(x-amz-bucket-region).amazon.com as endpoint. */
2821+
const char *pszRegionPtr =
2822+
(pszHeaders != nullptr)
2823+
? strstr(pszHeaders, "x-amz-bucket-region: ")
2824+
: nullptr;
2825+
if (pszRegionPtr != nullptr)
28152826
{
2816-
/* If we have a body with
2817-
<Error><Code>PermanentRedirect</Code><Message>The bucket you are
2818-
attempting to access must be addressed using the specified endpoint.
2819-
Please send all future requests to this
2820-
endpoint.</Message><Bucket>bucket.with.dot</Bucket><Endpoint>bucket.with.dot.s3.amazonaws.com</Endpoint></Error>
2821-
and headers like
2822-
x-amz-bucket-region: eu-west-1
2823-
and the bucket name has dot in it,
2824-
then we must use s3.$(x-amz-bucket-region).amazon.com as endpoint.
2825-
See #7154 */
2826-
const char *pszRegionPtr =
2827-
(pszHeaders != nullptr)
2828-
? strstr(pszHeaders, "x-amz-bucket-region: ")
2829-
: nullptr;
2830-
if (strchr(m_osBucket.c_str(), '.') != nullptr &&
2831-
pszRegionPtr != nullptr)
2827+
std::string osRegion(pszRegionPtr +
2828+
strlen("x-amz-bucket-region: "));
2829+
size_t nPos = osRegion.find('\r');
2830+
if (nPos != std::string::npos)
2831+
osRegion.resize(nPos);
2832+
if (strncmp(pszEndpoint, m_osBucket.c_str(), m_osBucket.size()) ==
2833+
0 &&
2834+
pszEndpoint[m_osBucket.size()] == '.')
28322835
{
2833-
std::string osRegion(pszRegionPtr +
2834-
strlen("x-amz-bucket-region: "));
2835-
size_t nPos = osRegion.find('\r');
2836-
if (nPos != std::string::npos)
2837-
osRegion.resize(nPos);
2838-
SetEndpoint(
2839-
CPLSPrintf("s3.%s.amazonaws.com", osRegion.c_str()));
2840-
SetRegion(osRegion.c_str());
2841-
CPLDebug(AWS_DEBUG_KEY, "Switching to endpoint %s",
2842-
m_osEndpoint.c_str());
2843-
CPLDebug(AWS_DEBUG_KEY, "Switching to region %s",
2844-
m_osRegion.c_str());
2845-
CPLDestroyXMLNode(psTree);
2846-
if (!bIsTemporaryRedirect)
2847-
VSIS3UpdateParams::UpdateMapFromHandle(this);
2848-
return true;
2836+
pszEndpoint += m_osBucket.size() + 1;
28492837
}
28502838

2839+
SetEndpoint(pszEndpoint);
2840+
SetRegion(osRegion.c_str());
2841+
CPLDebug(AWS_DEBUG_KEY, "Switching to endpoint %s",
2842+
m_osEndpoint.c_str());
2843+
CPLDebug(AWS_DEBUG_KEY, "Switching to region %s",
2844+
m_osRegion.c_str());
2845+
CPLDestroyXMLNode(psTree);
2846+
if (!bIsTemporaryRedirect)
2847+
VSIS3UpdateParams::UpdateMapFromHandle(this);
2848+
return true;
2849+
}
2850+
2851+
if (!m_bUseVirtualHosting &&
2852+
m_osBucket.find('.') == std::string::npos &&
2853+
strncmp(pszEndpoint, m_osBucket.c_str(), m_osBucket.size()) == 0 &&
2854+
pszEndpoint[m_osBucket.size()] == '.')
2855+
{
28512856
m_bUseVirtualHosting = true;
28522857
CPLDebug(AWS_DEBUG_KEY, "Switching to virtual hosting");
28532858
}
2859+
28542860
SetEndpoint(m_bUseVirtualHosting ? pszEndpoint + m_osBucket.size() + 1
28552861
: pszEndpoint);
28562862
CPLDebug(AWS_DEBUG_KEY, "Switching to endpoint %s",

0 commit comments

Comments
 (0)