Skip to content

Commit 004d6c0

Browse files
authored
fix(lib-storage): fix bucket duplication in hostname (#4157)
1 parent 47ca922 commit 004d6c0

File tree

2 files changed

+52
-7
lines changed

2 files changed

+52
-7
lines changed

lib/lib-storage/src/Upload.spec.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ const putObjectTaggingMock = jest.fn().mockResolvedValue({
2121
Success: "Tags have been applied!",
2222
});
2323

24-
const endpointMock = jest.fn().mockResolvedValue({
25-
hostname: "s3.region.amazonaws.com",
24+
let hostname = "s3.region.amazonaws.com";
25+
const endpointMock = jest.fn().mockImplementation(() => ({
26+
hostname,
2627
port: undefined,
2728
protocol: "https:",
2829
path: "/",
2930
query: undefined,
30-
});
31+
}));
3132

3233
import { EventEmitter, Readable } from "stream";
3334

@@ -64,11 +65,11 @@ jest.mock("@aws-sdk/client-s3", () => ({
6465
PutObjectCommand: putObjectMock,
6566
}));
6667

68+
import { AbortController } from "@aws-sdk/abort-controller";
6769
import { CompleteMultipartUploadCommandOutput, S3, S3Client } from "@aws-sdk/client-s3";
6870
import { createHash } from "crypto";
6971

7072
import { Progress, Upload } from "./index";
71-
import { AbortController } from "@aws-sdk/abort-controller";
7273

7374
const DEFAULT_PART_SIZE = 1024 * 1024 * 5;
7475

@@ -245,6 +246,42 @@ describe(Upload.name, () => {
245246
expect(result.Location).toEqual("https://example-bucket.s3.region.amazonaws.com/example-key");
246247
});
247248

249+
describe("bucket hostname deduplication", () => {
250+
afterEach(() => {
251+
hostname = "s3.region.amazonaws.com";
252+
});
253+
it("should dedupe bucket in endpoint hostname when forcePathStyle = false", async () => {
254+
hostname = "example-bucket.example-host.com";
255+
const buffer = Buffer.from("");
256+
const actionParams = { ...params, Body: buffer };
257+
const upload = new Upload({
258+
params: actionParams,
259+
client: new S3({
260+
forcePathStyle: false,
261+
}),
262+
});
263+
const result = (await upload.done()) as CompleteMultipartUploadCommandOutput;
264+
expect(result.Key).toEqual("example-key");
265+
expect(result.Bucket).toEqual("example-bucket");
266+
expect(result.Location).toEqual("https://example-bucket.example-host.com/example-key");
267+
});
268+
it("should prepend bucket in endpoint hostname when it does not already contain it and forcePathStyle = false", async () => {
269+
hostname = "example-host.com";
270+
const buffer = Buffer.from("");
271+
const actionParams = { ...params, Body: buffer };
272+
const upload = new Upload({
273+
params: actionParams,
274+
client: new S3({
275+
forcePathStyle: false,
276+
}),
277+
});
278+
const result = (await upload.done()) as CompleteMultipartUploadCommandOutput;
279+
expect(result.Key).toEqual("example-key");
280+
expect(result.Bucket).toEqual("example-bucket");
281+
expect(result.Location).toEqual("https://example-bucket.example-host.com/example-key");
282+
});
283+
});
284+
248285
it("should return a Location field formatted in path style when forcePathStyle is true", async () => {
249286
const buffer = Buffer.from("");
250287
const actionParams = { ...params, Body: buffer };

lib/lib-storage/src/Upload.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,17 @@ export class Upload extends EventEmitter {
153153
.join("/");
154154
const locationBucket = extendedEncodeURIComponent(this.params.Bucket!);
155155

156-
const Location: string = this.client.config.forcePathStyle
157-
? `${endpoint.protocol}//${endpoint.hostname}/${locationBucket}/${locationKey}`
158-
: `${endpoint.protocol}//${locationBucket}.${endpoint.hostname}/${locationKey}`;
156+
const Location: string = (() => {
157+
const endpointHostnameIncludesBucket = endpoint.hostname.startsWith(`${locationBucket}.`);
158+
const forcePathStyle = this.client.config.forcePathStyle;
159+
if (forcePathStyle) {
160+
return `${endpoint.protocol}//${endpoint.hostname}/${locationBucket}/${locationKey}`;
161+
}
162+
if (endpointHostnameIncludesBucket) {
163+
return `${endpoint.protocol}//${endpoint.hostname}/${locationKey}`;
164+
}
165+
return `${endpoint.protocol}//${locationBucket}.${endpoint.hostname}/${locationKey}`;
166+
})();
159167

160168
this.singleUploadResult = {
161169
...putResult,

0 commit comments

Comments
 (0)