Skip to content

Commit 98dc30c

Browse files
committed
Adds support for vhost-style s3 buckets
1 parent 0f941aa commit 98dc30c

File tree

2 files changed

+53
-16
lines changed

2 files changed

+53
-16
lines changed

get_s3.go

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -213,28 +213,49 @@ func (g *S3Getter) parseUrl(u *url.URL) (region, bucket, path, version string, c
213213
// any other S3 compliant service. S3 has a predictable
214214
// url as others do not
215215
if strings.Contains(u.Host, "amazonaws.com") {
216-
// Expected host style: s3.amazonaws.com. They always have 3 parts,
217-
// although the first may differ if we're accessing a specific region.
216+
// Amazon S3 supports both virtual-hosted–style and path-style URLs to access a bucket, although path-style is deprecated
217+
// In both cases few older regions supports dash-style region indication (s3-Region) even if AWS discourages their use.
218+
// The same bucket could be reached with:
219+
// bucket.s3.region.amazonaws.com/path
220+
// bucket.s3-region.amazonaws.com/path
221+
// s3.amazonaws.com/bucket/path
222+
// s3-region.amazonaws.com/bucket/path
223+
218224
hostParts := strings.Split(u.Host, ".")
219-
if len(hostParts) != 3 {
220-
err = fmt.Errorf("URL is not a valid S3 URL")
221-
return
222-
}
225+
switch len(hostParts) {
226+
// path-style
227+
case 3:
228+
// Parse the region out of the first part of the host
229+
region = strings.TrimPrefix(strings.TrimPrefix(hostParts[0], "s3-"), "s3")
230+
if region == "" {
231+
region = "us-east-1"
232+
}
233+
pathParts := strings.SplitN(u.Path, "/", 3)
234+
bucket = pathParts[1]
235+
path = pathParts[2]
236+
// vhost-style, dash region indication
237+
case 4:
238+
// Parse the region out of the first part of the host
239+
region = strings.TrimPrefix(strings.TrimPrefix(hostParts[1], "s3-"), "s3")
240+
if region == "" {
241+
err = fmt.Errorf("URL is not a valid S3 URL")
242+
return
243+
}
244+
pathParts := strings.SplitN(u.Path, "/", 2)
245+
bucket = hostParts[0]
246+
path = pathParts[1]
247+
//vhost-style, dot region indication
248+
case 5:
249+
region = hostParts[2]
250+
pathParts := strings.SplitN(u.Path, "/", 2)
251+
bucket = hostParts[0]
252+
path = pathParts[1]
223253

224-
// Parse the region out of the first part of the host
225-
region = strings.TrimPrefix(strings.TrimPrefix(hostParts[0], "s3-"), "s3")
226-
if region == "" {
227-
region = "us-east-1"
228254
}
229-
230-
pathParts := strings.SplitN(u.Path, "/", 3)
231-
if len(pathParts) != 3 {
255+
if len(hostParts) < 3 && len(hostParts) > 5 {
232256
err = fmt.Errorf("URL is not a valid S3 URL")
233257
return
234258
}
235-
236-
bucket = pathParts[1]
237-
path = pathParts[2]
238259
version = u.Query().Get("version")
239260

240261
} else {

get_s3_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,22 @@ func TestS3Getter_Url(t *testing.T) {
189189
path: "foo/bar.baz",
190190
version: "1234",
191191
},
192+
{
193+
name: "AWSVhostDot",
194+
url: "s3::https://bucket.s3.eu-west-1.amazonaws.com/foo/bar.baz?version=1234",
195+
region: "eu-west-1",
196+
bucket: "bucket",
197+
path: "foo/bar.baz",
198+
version: "1234",
199+
},
200+
{
201+
name: "AWSVhostDash",
202+
url: "s3::https://bucket.s3-eu-west-1.amazonaws.com/foo/bar.baz?version=1234",
203+
region: "eu-west-1",
204+
bucket: "bucket",
205+
path: "foo/bar.baz",
206+
version: "1234",
207+
},
192208
{
193209
name: "localhost-1",
194210
url: "s3::http://127.0.0.1:9000/test-bucket/hello.txt?aws_access_key_id=TESTID&aws_access_key_secret=TestSecret&region=us-east-2&version=1",

0 commit comments

Comments
 (0)