2
2
import logging
3
3
from urllib .parse import urlsplit , urlunsplit
4
4
5
- from localstack . config import LEGACY_S3_PROVIDER
5
+ from localstack import config
6
6
from localstack .constants import LOCALHOST_HOSTNAME
7
7
from localstack .http import Request , Response
8
8
from localstack .http .proxy import Proxy
13
13
14
14
LOG = logging .getLogger (__name__ )
15
15
16
- # virtual-host style: https://{bucket-name}.s3.{region}.localhost.localstack.cloud.com/{key-name}
17
- VHOST_REGEX_PATTERN = f"<regex('.*'):bucket>.s3.<regex('({ AWS_REGION_REGEX } \\ .)?'):region>{ LOCALHOST_HOSTNAME } <regex('(?::\\ d+)?'):port>"
16
+ # virtual-host style: https://{bucket-name}.s3.{region?}.{domain}:{port?}/{key-name}
17
+ # ex: https://{bucket-name}.s3.{region}.localhost.localstack.cloud.com:4566/{key-name}
18
+ # ex: https://{bucket-name}.s3.{region}.amazonaws.com/{key-name}
19
+ VHOST_REGEX_PATTERN = f"<regex('.*'):bucket>.s3.<regex('({ AWS_REGION_REGEX } \\ .)?'):region><regex('.*'):domain><regex('(?::\\ d+)?'):port>"
18
20
19
21
# path addressed request with the region in the hostname
20
22
# https://s3.{region}.localhost.localstack.cloud.com/{bucket-name}/{key-name}
21
23
PATH_WITH_REGION_PATTERN = (
22
- f"s3.<regex('({ AWS_REGION_REGEX } \\ .)'):region>{ LOCALHOST_HOSTNAME } <regex('(?::\\ d+)?'):port>"
24
+ f"s3.<regex('({ AWS_REGION_REGEX } \\ .)'):region><regex('.*'):domain> <regex('(?::\\ d+)?'):port>"
23
25
)
24
26
25
27
@@ -31,7 +33,7 @@ class S3VirtualHostProxyHandler:
31
33
32
34
def __call__ (self , request : Request , ** kwargs ) -> Response :
33
35
# TODO region pattern currently not working -> removing it from url
34
- rewritten_url = self ._rewrite_url (request .url , kwargs . get ( "bucket" ), kwargs . get ( "region" ) )
36
+ rewritten_url = self ._rewrite_url (url = request .url , ** kwargs )
35
37
36
38
LOG .debug (f"Rewritten original host url: { request .url } to path-style url: { rewritten_url } " )
37
39
@@ -41,7 +43,7 @@ def __call__(self, request: Request, **kwargs) -> Response:
41
43
copied_headers [S3_VIRTUAL_HOST_FORWARDED_HEADER ] = request .headers ["host" ]
42
44
# do not preserve the Host when forwarding (to avoid an endless loop)
43
45
with Proxy (
44
- forward_base_url = f" { forward_to_url . scheme } :// { forward_to_url . netloc } " ,
46
+ forward_base_url = config . get_edge_url () ,
45
47
preserve_host = False ,
46
48
) as proxy :
47
49
forwarded = proxy .forward (
@@ -53,18 +55,21 @@ def __call__(self, request: Request, **kwargs) -> Response:
53
55
return forwarded
54
56
55
57
@staticmethod
56
- def _rewrite_url (url : str , bucket : str , region : str ) -> str :
58
+ def _rewrite_url (url : str , domain : str , bucket : str , region : str , port : str , ** kwargs ) -> str :
57
59
"""
58
60
Rewrites the url so that it can be forwarded to moto. Used for vhost-style and for any url that contains the region.
59
61
60
62
For vhost style: removes the bucket-name from the host-name and adds it as path
61
- E.g. http://my-bucket.s3.localhost.localstack.cloud:4566 -> http://s3.localhost.localstack.cloud:4566/my-bucket
63
+ E.g. https://bucket.s3.localhost.localstack.cloud:4566 -> https://s3.localhost.localstack.cloud:4566/bucket
64
+ E.g. https://bucket.s3.amazonaws.com -> https://s3.localhost.localstack.cloud:4566/bucket
62
65
63
66
If the region is contained in the host-name we remove it (for now) as moto cannot handle the region correctly
64
67
65
68
:param url: the original url
69
+ :param domain: the domain name
66
70
:param bucket: the bucket name
67
71
:param region: the region name
72
+ :param port: the port number (if specified in the original request URL), or an empty string
68
73
:return: re-written url as string
69
74
"""
70
75
splitted = urlsplit (url )
@@ -79,10 +84,17 @@ def _rewrite_url(url: str, bucket: str, region: str) -> str:
79
84
if region :
80
85
netloc = netloc .replace (f"{ region } " , "" )
81
86
87
+ # the user can specify whatever domain & port he wants in the Host header
88
+ # we need to make sure we're redirecting the request to our edge URL, possibly s3.localhost.localstack.cloud
89
+ host = f"{ domain } :{ port } " if port else domain
90
+ edge_host = f"{ LOCALHOST_HOSTNAME } :{ config .get_edge_port_http ()} "
91
+ if host != edge_host :
92
+ netloc = netloc .replace (host , edge_host )
93
+
82
94
return urlunsplit ((splitted .scheme , netloc , path , splitted .query , splitted .fragment ))
83
95
84
96
85
- @hooks .on_infra_ready (should_load = not LEGACY_S3_PROVIDER )
97
+ @hooks .on_infra_ready (should_load = not config . LEGACY_S3_PROVIDER )
86
98
def register_virtual_host_routes ():
87
99
"""
88
100
Registers the S3 virtual host handler into the edge router.
0 commit comments