Skip to content

Commit 3d7b036

Browse files
fix: compatibility for S3
Put bucket into host instead of path. Add option "s3_bucket_in_path" to use deprecated APIs. I wonder why the offical SDK do not update api definition. They instead do it with monkey patch code?!
1 parent 8ffdb73 commit 3d7b036

File tree

2 files changed

+68
-34
lines changed

2 files changed

+68
-34
lines changed

src/resty/aws/init.lua

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,13 @@ local function generate_service_methods(service)
317317
self.config.signatureVersion = "none"
318318
end
319319

320+
local bucket
321+
if not self.config.s3_bucket_in_path then
322+
bucket = params.Bucket
323+
end
324+
320325
-- sign the request according to the signature version required
321-
local signed_request, err = sign_request(self.config, request)
326+
local signed_request, err = sign_request(self.config, request, bucket)
322327
if old_sig then
323328
-- revert the patched signatureVersion
324329
self.config.signatureVersion = old_sig

src/resty/aws/request/signatures/v4.lua

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,60 @@ local function derive_signing_key(kSecret, date, region, service)
100100
end
101101

102102

103+
local function get_host(config)
104+
local host = config.endpoint
105+
do
106+
local s, e = host:find("://")
107+
if s then
108+
-- the "globalSSL" one from the region_config_data file
109+
local scheme = host:sub(1, s-1):lower()
110+
host = host:sub(e+1, -1)
111+
if config.tls == nil then
112+
config.tls = scheme == "https"
113+
end
114+
end
115+
end
116+
117+
local tls = config.tls
118+
local port = config.port or (tls and 443 or 80)
119+
120+
local host_header do -- If the "standard" port is not in use, the port should be added to the Host header
121+
local with_port
122+
if tls then
123+
with_port = port ~= 443
124+
else
125+
with_port = port ~= 80
126+
end
127+
if with_port then
128+
host_header = string.format("%s:%d", host, port)
129+
else
130+
host_header = host
131+
end
132+
end
133+
134+
return host_header
135+
end
136+
137+
138+
local function s3_patch(request, bucket)
139+
if not bucket then
140+
return
141+
end
142+
143+
request.headers.Host = bucket .. "." .. request.headers.Host
144+
145+
local path = request.path
146+
if bucket and path then
147+
path = path:sub(#bucket + 2)
148+
if path == "/" then
149+
path = ""
150+
end
151+
152+
request.path = path
153+
end
154+
end
155+
156+
103157
-- config to contain:
104158
-- config.endpoint: hostname to connect to
105159
-- config.credentials: the Credentials class to use
@@ -122,7 +176,10 @@ end
122176
-- tbl.timestamp: number defaults to 'ngx.time()''
123177
-- tbl.global_endpoint: if true, then use "us-east-1" as signing region and different
124178
-- hostname template: see https://github.com/aws/aws-sdk-js/blob/ae07e498e77000e55da70b20996dc8fd2f8b3051/lib/region_config_data.json
125-
local function prepare_awsv4_request(config, request_data)
179+
local function prepare_awsv4_request(config, request_data, bucket)
180+
request_data.headers = request_data.headers or {}
181+
request_data.headers.Host = get_host(config)
182+
s3_patch(request_data, bucket)
126183
local region = config.signingRegion or config.region
127184
local service = config.endpointPrefix or config.targetPrefix -- TODO: targetPrefix as fallback, correct???
128185
local request_method = request_data.method -- TODO: should this get a fallback/default??
@@ -141,7 +198,7 @@ local function prepare_awsv4_request(config, request_data)
141198
canonical_querystring = canonicalise_query_string(query)
142199
end
143200

144-
local req_headers = request_data.headers or {}
201+
local req_headers = request_data.headers
145202
local req_payload = request_data.body
146203

147204
-- get credentials
@@ -157,46 +214,18 @@ local function prepare_awsv4_request(config, request_data)
157214
end
158215

159216
local tls = config.tls
160-
local host = config.endpoint
161-
do
162-
local s, e = host:find("://")
163-
if s then
164-
-- the "globalSSL" one from the region_config_data file
165-
local scheme = host:sub(1, s-1):lower()
166-
host = host:sub(e+1, -1)
167-
if config.tls == nil then
168-
config.tls = scheme == "https"
169-
end
170-
end
171-
end
172217

173-
if tls == nil then
174-
tls = true
175-
end
176218
local port = config.port or (tls and 443 or 80)
177219
local timestamp = ngx.time()
178220
local req_date = os.date("!%Y%m%dT%H%M%SZ", timestamp)
179221
local date = os.date("!%Y%m%d", timestamp)
180222

181-
local host_header do -- If the "standard" port is not in use, the port should be added to the Host header
182-
local with_port
183-
if tls then
184-
with_port = port ~= 443
185-
else
186-
with_port = port ~= 80
187-
end
188-
if with_port then
189-
host_header = string.format("%s:%d", host, port)
190-
else
191-
host_header = host
192-
end
193-
end
194-
195223
local headers = {
196224
["X-Amz-Date"] = req_date,
197-
["Host"] = host_header,
225+
["Host"] = request_data.Host,
198226
["X-Amz-Security-Token"] = session_token,
199227
}
228+
request_data.Host = nil
200229

201230
local S3 = config.signatureVersion == "s3"
202231

@@ -289,7 +318,7 @@ local function prepare_awsv4_request(config, request_data)
289318

290319
return {
291320
--url = url, -- "https://lambda.us-east-1.amazon.com:443/some/path?query1=val1"
292-
host = host, -- "lambda.us-east-1.amazon.com"
321+
host = headers.Host, -- "lambda.us-east-1.amazon.com"
293322
port = port, -- 443
294323
tls = tls, -- true
295324
path = path or canonicalURI, -- "/some/path"

0 commit comments

Comments
 (0)