1-
2- const Minio = require ( "minio" ) ;
31const request = require ( "supertest" ) ;
2+ const container = require ( "./support/container.js" ) ;
3+ const s3Mock = require ( "./support/s3Mock.js" ) ;
4+
5+ const TEST_NAME = "base" ;
46
57const FILES = {
68 "a.txt" : {
@@ -18,56 +20,123 @@ const FILES = {
1820 "Throw it away!"
1921 "With not one thing, what there is to throw away?"
2022 "Then carry it off!"
23+ ` ,
24+ } ,
25+ "b/c/=" : {
26+ content : `
27+ This is an awful filename.
28+ このフィール名を選ばないでください
29+ `
30+ } ,
31+ "b/c/@" : {
32+ content : ""
33+ } ,
34+ "b/c/'(1).txt" : {
35+ content : "In the midst of movement and chaos, keep stillness inside of you."
36+ } ,
37+ "a/plus+plus.txt" : {
38+ content : `
39+ 代悲白頭翁 Lament for the White-Haired Old Man
40+ 洛陽城東桃李花 In the east of Luoyang City, Peach blossoms abound
41+ 飛來飛去落誰家 Their petals float around, coming and going, to whose house will they fall?
42+ 洛陽女児惜顔色 Girls in Luoyang cherish their complexion
43+ 行逢落花長歎息 They breathe a deep sigh upon seeing the petals fall
44+ 今年花落顔色改 This year the petals fall and their complexion changes
45+ 明年花開復誰在 Who will be there when the flowers bloom next year?
46+ 已見松柏摧為薪 I've seen the pines and cypresses destroyed and turned into firewood
47+ 更聞桑田変成海 I hear that the mulberry fields have fallen into the sea
48+ 古人無復洛城東 The people of old never came back to the east of Luoyang City
49+ 今人還對落花風 The people of today likewise face the falling flowers in the wind
50+ 年年歳歳花相似 Year after year, flowers look alike
51+ 歳歳年年人不同 Year after year, the people are not the same
52+ 寄言全盛紅顔子 I want you to get this message, my child, you are in your prime, with a rosy complexion
53+ 應憐半死白頭翁 Take pity on the half-dead white-haired old man
54+ 此翁白頭真可憐 You really must take pity on this white-haired old man
55+ 伊昔紅顔美少年 For once upon a time, I used to be a red-faced handsome young man
56+ 公子王孫芳樹下 A child of noble birth under a fragrant tree
57+ 清歌妙舞落花前 Singing and dancing in front of the falling petals
58+ 光禄池臺開錦繍 At the platform before the mirror pond, beautiful autumn leaves opening all around
59+ 将軍楼閣畫神仙 The general’s pavilion is painted with gods and goddesses
60+ 一朝臥病無相識 Once I was sick and no one knew me
61+ 三春行楽在誰邉 Who will be at the shore for the spring outing?
62+ 宛轉蛾眉能幾時 For how long will the moths gracefully turn about?
63+ 須臾鶴髪亂如絲 The crane’s feathers are like tangled threads for just a moment
64+ 但看古来歌舞地 Yet, look at the ancient places of song and dance
65+ 惟有黄昏鳥雀悲 Only in twilight, do the birds lament
66+ `
67+ } ,
68+ "системы/%bad%file%name%" : {
69+ content : `
70+ Filename encoding issues are hard.
71+
2172 `
2273 }
2374} ;
2475
2576const BUCKET_NAME = "bucket-2" ;
26- const GATEWAY_HOST = "localhost" ;
27- const GATEWAY_PORT = "8989" ;
28- const GATEWAY_BASE_URL = `http://${ GATEWAY_HOST } :${ GATEWAY_PORT } ` ;
29-
30- beforeAll ( async ( ) => {
31- const minioClient = new Minio . Client ( {
32- endPoint : "localhost" ,
33- port : 9090 ,
34- useSSL : false ,
35- accessKey : 'AKIAIOSFODNN7EXAMPLE' ,
36- secretKey : 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' ,
37- } ) ;
3877
39- await ensureBucketWithObjects ( minioClient , BUCKET_NAME , FILES ) ;
78+ // Config for the running container per test
79+
80+ const CONFIG = container . Config ( {
81+ env : {
82+ S3_BUCKET_NAME : BUCKET_NAME ,
83+ AWS_ACCESS_KEY_ID : "AKIAIOSFODNN7EXAMPLE" ,
84+ AWS_SECRET_ACCESS_KEY : "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" ,
85+ S3_SERVER : "minio" ,
86+ S3_SERVER_PORT : "9000" ,
87+ S3_SERVER_PROTO : "http" ,
88+ S3_REGION : "us-east-1" ,
89+ DEBUG : "true" ,
90+ S3_STYLE : "virtual" ,
91+ ALLOW_DIRECTORY_LIST : "false" ,
92+ PROVIDE_INDEX_PAGE : "" ,
93+ APPEND_SLASH_FOR_POSSIBLE_DIRECTORY : "" ,
94+ STRIP_LEADING_DIRECTORY_PATH : "" ,
95+ PREFIX_LEADING_DIRECTORY_PATH : "" ,
96+ AWS_SIGS_VERSION : "4" ,
97+ STATIC_SITE_HOSTING : "" ,
98+ PROXY_CACHE_MAX_SIZE : "10g" ,
99+ PROXY_CACHE_INACTIVE : "60m" ,
100+ PROXY_CACHE_VALID_OK : "1h" ,
101+ PROXY_CACHE_VALID_NOTFOUND : "1m" ,
102+ PROXY_CACHE_VALID_FORBIDDEN : "30s" ,
103+ } ,
104+ dockerfileName : "Dockerfile.oss" ,
105+ testName : TEST_NAME ,
106+ networkName : "s3-gateway-test" ,
40107} ) ;
41108
42- async function ensureBucketWithObjects ( s3Client , bucketName , objects ) {
43- if ( await s3Client . bucketExists ( BUCKET_NAME ) ) {
44- await s3Client . removeObjects ( BUCKET_NAME , Object . keys ( FILES ) ) ;
45- await s3Client . removeBucket ( BUCKET_NAME ) ;
109+ const minioClient = s3Mock . Client ( "localhost" , 9090 , "AKIAIOSFODNN7EXAMPLE" , "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" ) ;
110+
111+ beforeAll ( async ( ) => {
112+ try {
113+ await container . stop ( CONFIG ) ;
114+ } catch ( e ) {
115+ console . log ( "no container to stop" ) ;
46116 }
47117
48- await s3Client . makeBucket ( BUCKET_NAME , 'us-east-1' ) ;
118+ await s3Mock . ensureBucketWithObjects ( minioClient , BUCKET_NAME , FILES ) ;
119+ await container . build ( CONFIG ) ;
120+ await container . start ( CONFIG ) ;
121+ } ) ;
122+
123+ afterAll ( async ( ) => {
124+ await container . stop ( CONFIG ) ;
125+ await s3Mock . deleteBucket ( minioClient , BUCKET_NAME ) ;
126+ } ) ;
49127
50- for ( const path of Object . keys ( FILES ) ) {
51- console . log ( `now loading file ${ path } ` ) ;
52- let buf = Buffer . from ( FILES [ path ] . content , "utf-8" ) ;
53- let res = await s3Client . putObject ( BUCKET_NAME , path , buf ) ;
54- console . log ( `Uploaded file: ${ JSON . stringify ( res ) } ` ) ;
55- }
56- }
57128
58129describe ( "Ordinary filenames" , ( ) => {
59130 test ( "simple url" , async ( ) => {
60131 const objectPath = "a.txt" ;
61- const res = await request ( GATEWAY_BASE_URL )
62- . get ( `/${ objectPath } ` ) ;
63-
132+ const res = await request ( CONFIG . testContainer . baseUrl ) . get ( `/${ objectPath } ` ) ;
64133 expect ( res . statusCode ) . toBe ( 200 ) ;
65134 expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
66135 } ) ;
67136
68137 test ( "many params that should be stripped" , async ( ) => {
69138 const objectPath = "a.txt" ;
70- const res = await request ( GATEWAY_BASE_URL )
139+ const res = await request ( CONFIG . testContainer . baseUrl )
71140 . get ( "/a.txt?some=param&that=should&be=stripped#aaah" )
72141 . set ( "accept" , "binary/octet-stream" ) ;
73142
@@ -77,27 +146,28 @@ describe("Ordinary filenames", () => {
77146
78147 test ( "with a more complex path" , async ( ) => {
79148 const objectPath = "b/c/d.txt" ;
80- const res = await request ( GATEWAY_BASE_URL )
149+ const res = await request ( CONFIG . testContainer . baseUrl )
81150 . get ( "/b/c/d.txt" )
82151 . set ( "accept" , "binary/octet-stream" ) ;
83152
84153 expect ( res . statusCode ) . toBe ( 200 ) ;
85154 expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
86155 } ) ;
87156
88- test ( "with a more complex path" , async ( ) => {
157+ test . skip ( "with dot segments in the path" , async ( ) => {
89158 const objectPath = "b/e.txt" ;
90- const res = await request ( GATEWAY_BASE_URL )
159+ const res = await request ( CONFIG . testContainer . baseUrl )
91160 . get ( "/b/c/../e.txt" )
92161 . set ( "accept" , "binary/octet-stream" ) ;
93162
163+ const reqData = JSON . parse ( JSON . stringify ( res ) ) . req ;
94164 expect ( res . statusCode ) . toBe ( 200 ) ;
95165 expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
96166 } ) ;
97167
98168 test ( "another simple path" , async ( ) => {
99169 const objectPath = "b/e.txt" ;
100- const res = await request ( GATEWAY_BASE_URL )
170+ const res = await request ( CONFIG . testContainer . baseUrl )
101171 . get ( "/b/e.txt" )
102172 . set ( "accept" , "binary/octet-stream" ) ;
103173
@@ -107,7 +177,7 @@ describe("Ordinary filenames", () => {
107177
108178 test ( "too many forward slashes" , async ( ) => {
109179 const objectPath = "b/e.txt" ;
110- const res = await request ( GATEWAY_BASE_URL )
180+ const res = await request ( CONFIG . testContainer . baseUrl )
111181 . get ( "/b//e.txt" )
112182 . set ( "accept" , "binary/octet-stream" ) ;
113183
@@ -116,9 +186,12 @@ describe("Ordinary filenames", () => {
116186 } ) ;
117187
118188 test ( "very long file name" , async ( ) => {
119- const objectPath = "a/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.txt" ;
120- const res = await request ( GATEWAY_BASE_URL )
121- . get ( "/a/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.txt" )
189+ const objectPath =
190+ "a/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.txt" ;
191+ const res = await request ( CONFIG . testContainer . baseUrl )
192+ . get (
193+ "/a/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.txt" ,
194+ )
122195 . set ( "accept" , "binary/octet-stream" ) ;
123196
124197 expect ( res . statusCode ) . toBe ( 200 ) ;
@@ -127,23 +200,53 @@ describe("Ordinary filenames", () => {
127200} ) ;
128201
129202describe ( "strange file names and encodings" , ( ) => {
203+ test ( "URI encoded equal sign as file name" , async ( ) => {
204+ const objectPath = "b/c/=" ;
205+ const res = await request ( CONFIG . testContainer . baseUrl )
206+ . get ( "/b/c/%3D" )
207+ . set ( "accept" , "binary/octet-stream" ) ;
208+
209+ expect ( res . statusCode ) . toBe ( 200 ) ;
210+ expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
211+ } ) ;
130212
131- } )
213+ test ( "URI encoded @ symbol as file name" , async ( ) => {
214+ const objectPath = "b/c/@" ;
215+ const res = await request ( CONFIG . testContainer . baseUrl )
216+ . get ( "/b/c/%40" )
217+ . set ( "accept" , "binary/octet-stream" ) ;
218+
219+ expect ( res . statusCode ) . toBe ( 200 ) ;
220+ expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
221+ } ) ;
132222
133- // # We try to request URLs that are properly encoded as well as URLs that
134- // # are not properly encoded to understand what works and what does not.
223+ test ( "URI with encoded punctuation in file name" , async ( ) => {
224+ const objectPath = "b/c/'(1).txt" ;
225+ const res = await request ( CONFIG . testContainer . baseUrl )
226+ . get ( "/b/c/%27%281%29.txt" )
227+ . set ( "accept" , "binary/octet-stream" ) ;
135228
136- // # Weird filenames
137- // assertHttpRequestEquals "HEAD" "b/c/%3D" "200"
138- // assertHttpRequestEquals "HEAD" "b/c/=" "200"
229+ expect ( res . statusCode ) . toBe ( 200 ) ;
230+ expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
231+ } ) ;
139232
140- // assertHttpRequestEquals "HEAD" "b/c/%40" "200"
141- // assertHttpRequestEquals "HEAD" "b/c/@" "200"
233+ test ( "URI with encoded plus in file name" , async ( ) => {
234+ const objectPath = "a/plus+plus.txt" ;
235+ const res = await request ( CONFIG . testContainer . baseUrl )
236+ . get ( "/a/plus%2Bplus.txt" )
237+ . set ( "accept" , "binary/octet-stream" ) ;
142238
143- // assertHttpRequestEquals "HEAD" "b/c/%27%281%29.txt" "200"
144- // assertHttpRequestEquals "HEAD" "b/c/'(1).txt" "200"
239+ expect ( res . statusCode ) . toBe ( 200 ) ;
240+ expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
241+ } ) ;
145242
146- // # These URLs do not work unencoded
147- // assertHttpRequestEquals "HEAD" 'a/plus%2Bplus.txt' "200"
148- // assertHttpRequestEquals "HEAD" "%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B/%25bad%25file%25name%25" "200"
243+ test ( "URI with cyrillic script and punctuation in file name" , async ( ) => {
244+ const objectPath = "системы/%bad%file%name%" ;
245+ const res = await request ( CONFIG . testContainer . baseUrl )
246+ . get ( "/%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B/%25bad%25file%25name%25" )
247+ . set ( "accept" , "binary/octet-stream" ) ;
149248
249+ expect ( res . statusCode ) . toBe ( 200 ) ;
250+ expect ( res . text ) . toBe ( FILES [ objectPath ] . content ) ;
251+ } ) ;
252+ } ) ;
0 commit comments