@@ -32,6 +32,7 @@ import { randomUUID } from 'crypto'
32
32
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
33
33
import axios from 'axios'
34
34
import { createPresignedPost } from '@aws-sdk/s3-presigned-post'
35
+ import { getInvalidObjectName , getUnicodeObjectName } from './common'
35
36
36
37
const { s3ProtocolAccessKeySecret, s3ProtocolAccessKeyId, storageS3Region } = getConfig ( )
37
38
@@ -1402,5 +1403,150 @@ describe('S3 Protocol', () => {
1402
1403
expect ( resp . ok ) . toBeTruthy ( )
1403
1404
} )
1404
1405
} )
1406
+
1407
+ describe ( 'Object key names with Unicode characters' , ( ) => {
1408
+ it ( 'can be used with MultipartUpload commands' , async ( ) => {
1409
+ const bucketName = await createBucket ( client )
1410
+ const objectName = getUnicodeObjectName ( )
1411
+ const createMultiPartUpload = new CreateMultipartUploadCommand ( {
1412
+ Bucket : bucketName ,
1413
+ Key : objectName ,
1414
+ ContentType : 'image/jpg' ,
1415
+ CacheControl : 'max-age=2000' ,
1416
+ } )
1417
+ const createMultipartResp = await client . send ( createMultiPartUpload )
1418
+ expect ( createMultipartResp . UploadId ) . toBeTruthy ( )
1419
+ const uploadId = createMultipartResp . UploadId
1420
+
1421
+ const listMultipartUploads = new ListMultipartUploadsCommand ( {
1422
+ Bucket : bucketName ,
1423
+ } )
1424
+ const listMultipartResp = await client . send ( listMultipartUploads )
1425
+ expect ( listMultipartResp . Uploads ?. length ) . toBe ( 1 )
1426
+ expect ( listMultipartResp . Uploads ?. [ 0 ] . Key ) . toBe ( objectName )
1427
+
1428
+ const data = Buffer . alloc ( 1024 * 1024 * 2 )
1429
+ const uploadPart = new UploadPartCommand ( {
1430
+ Bucket : bucketName ,
1431
+ Key : objectName ,
1432
+ ContentLength : data . length ,
1433
+ UploadId : uploadId ,
1434
+ Body : data ,
1435
+ PartNumber : 1 ,
1436
+ } )
1437
+ const uploadPartResp = await client . send ( uploadPart )
1438
+ expect ( uploadPartResp . ETag ) . toBeTruthy ( )
1439
+
1440
+ const listParts = new ListPartsCommand ( {
1441
+ Bucket : bucketName ,
1442
+ Key : objectName ,
1443
+ UploadId : uploadId ,
1444
+ } )
1445
+ const listPartsResp = await client . send ( listParts )
1446
+ expect ( listPartsResp . Parts ?. length ) . toBe ( 1 )
1447
+
1448
+ const completeMultiPartUpload = new CompleteMultipartUploadCommand ( {
1449
+ Bucket : bucketName ,
1450
+ Key : objectName ,
1451
+ UploadId : uploadId ,
1452
+ MultipartUpload : {
1453
+ Parts : [
1454
+ {
1455
+ PartNumber : 1 ,
1456
+ ETag : uploadPartResp . ETag ,
1457
+ } ,
1458
+ ] ,
1459
+ } ,
1460
+ } )
1461
+ const completeMultipartResp = await client . send ( completeMultiPartUpload )
1462
+ expect ( completeMultipartResp . $metadata . httpStatusCode ) . toBe ( 200 )
1463
+ expect ( completeMultipartResp . Key ) . toEqual ( objectName )
1464
+ } )
1465
+
1466
+ it ( 'can be used with Put, List, and Delete Object commands' , async ( ) => {
1467
+ const bucketName = await createBucket ( client )
1468
+ const objectName = getUnicodeObjectName ( )
1469
+ const putObject = new PutObjectCommand ( {
1470
+ Bucket : bucketName ,
1471
+ Key : objectName ,
1472
+ Body : Buffer . alloc ( 1024 * 1024 * 1 ) ,
1473
+ } )
1474
+ const putObjectResp = await client . send ( putObject )
1475
+ expect ( putObjectResp . $metadata . httpStatusCode ) . toEqual ( 200 )
1476
+
1477
+ const listObjects = new ListObjectsCommand ( {
1478
+ Bucket : bucketName ,
1479
+ } )
1480
+ const listObjectsResp = await client . send ( listObjects )
1481
+ expect ( listObjectsResp . Contents ?. length ) . toBe ( 1 )
1482
+ expect ( listObjectsResp . Contents ?. [ 0 ] . Key ) . toBe ( objectName )
1483
+
1484
+ const listObjectsV2 = new ListObjectsV2Command ( {
1485
+ Bucket : bucketName ,
1486
+ } )
1487
+ const listObjectsV2Resp = await client . send ( listObjectsV2 )
1488
+ expect ( listObjectsV2Resp . Contents ?. length ) . toBe ( 1 )
1489
+ expect ( listObjectsV2Resp . Contents ?. [ 0 ] . Key ) . toBe ( objectName )
1490
+
1491
+ const getObject = new GetObjectCommand ( {
1492
+ Bucket : bucketName ,
1493
+ Key : objectName ,
1494
+ } )
1495
+ const getObjectResp = await client . send ( getObject )
1496
+ const getObjectRespData = await getObjectResp . Body ?. transformToByteArray ( )
1497
+ expect ( getObjectRespData ) . toBeTruthy ( )
1498
+ expect ( getObjectResp . ETag ) . toBeTruthy ( )
1499
+
1500
+ const deleteObjects = new DeleteObjectsCommand ( {
1501
+ Bucket : bucketName ,
1502
+ Delete : {
1503
+ Objects : [
1504
+ {
1505
+ Key : objectName ,
1506
+ } ,
1507
+ ] ,
1508
+ } ,
1509
+ } )
1510
+ const deleteObjectsResp = await client . send ( deleteObjects )
1511
+ expect ( deleteObjectsResp . Errors ) . toBeFalsy ( )
1512
+ expect ( deleteObjectsResp . Deleted ) . toEqual ( [
1513
+ {
1514
+ Key : objectName ,
1515
+ } ,
1516
+ ] )
1517
+
1518
+ const getObjectDeleted = new GetObjectCommand ( {
1519
+ Bucket : bucketName ,
1520
+ Key : objectName ,
1521
+ } )
1522
+ try {
1523
+ await client . send ( getObjectDeleted )
1524
+ throw new Error ( 'Should not reach here' )
1525
+ } catch ( e ) {
1526
+ expect ( ( e as S3ServiceException ) . $metadata . httpStatusCode ) . toEqual ( 404 )
1527
+ }
1528
+ } )
1529
+
1530
+ it ( 'should not upload if the name contains invalid characters' , async ( ) => {
1531
+ const bucketName = await createBucket ( client )
1532
+ const invalidObjectName = getInvalidObjectName ( )
1533
+ try {
1534
+ const putObject = new PutObjectCommand ( {
1535
+ Bucket : bucketName ,
1536
+ Key : invalidObjectName ,
1537
+ Body : Buffer . alloc ( 1024 * 1024 * 1 ) ,
1538
+ } )
1539
+ await client . send ( putObject )
1540
+ throw new Error ( 'Should not reach here' )
1541
+ } catch ( e ) {
1542
+ expect ( ( e as Error ) . message ) . not . toBe ( 'Should not reach here' )
1543
+ expect ( ( e as S3ServiceException ) . $metadata . httpStatusCode ) . toEqual ( 400 )
1544
+ expect ( ( e as S3ServiceException ) . name ) . toEqual ( 'InvalidKey' )
1545
+ expect ( ( e as S3ServiceException ) . message ) . toEqual (
1546
+ `Invalid key: ${ encodeURIComponent ( invalidObjectName ) } `
1547
+ )
1548
+ }
1549
+ } )
1550
+ } )
1405
1551
} )
1406
1552
} )
0 commit comments