Skip to content

Commit 93cb648

Browse files
committed
Merge branch 'master' into issue/40
2 parents 21cd23c + b8c407f commit 93cb648

File tree

16 files changed

+250
-54
lines changed

16 files changed

+250
-54
lines changed

.github/workflows/main.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ jobs:
1313
build:
1414
runs-on: ubuntu-latest
1515

16+
if: github.ref != 'refs/heads/master'
17+
steps:
18+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
19+
- uses: actions/checkout@v2
20+
21+
- name: Install dependencies
22+
run: sudo apt-get install -y wait-for-it
23+
- name: Run tests - latest njs version
24+
run: ./test.sh latest-njs-oss
25+
- name: Run tests - stable njs version
26+
run: ./test.sh oss
27+
28+
build_and_deploy:
29+
runs-on: ubuntu-latest
30+
31+
if: github.ref == 'refs/heads/master'
1632
steps:
1733
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
1834
- uses: actions/checkout@v2

Dockerfile.oss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM nginx:1.23.1
22

33
ENV NGINX_VERSION "1.23.1"
4-
ENV NJS_VERSION 0.7.6
4+
ENV NJS_VERSION 0.7.7
55

66
ENV PROXY_CACHE_VALID_OK "1h"
77
ENV PROXY_CACHE_VALID_NOTFOUND "1m"

Dockerfile.plus

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM debian:bullseye-slim
22

33
ENV NGINX_PLUS_VERSION 27-1
44
ENV NGINX_VERSION 1.21.6
5-
ENV NJS_VERSION 27+0.7.4-1
5+
ENV NJS_VERSION 27+0.7.7-1
66
ENV XSLT_VERSION 27-1
77

88
ENV PROXY_CACHE_VALID_OK "1h"

common/docker-entrypoint.d/00-check-for-required-env.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ if [ "${AWS_SIGS_VERSION}" != "2" ] && [ "${AWS_SIGS_VERSION}" != "4" ]; then
5050
failed=1
5151
fi
5252

53+
parseBoolean() {
54+
case "$1" in
55+
TRUE | true | True | YES | Yes | 1)
56+
echo 1
57+
;;
58+
*)
59+
echo 0
60+
;;
61+
esac
62+
}
63+
64+
if [ "$(parseBoolean ${ALLOW_DIRECTORY_LIST})" == "1" ] && [ "$(parseBoolean ${PROVIDE_INDEX_PAGE})" == "1" ]; then
65+
>&2 echo "ALLOW_DIRECTORY_LIST and PROVIDE_INDEX_PAGE cannot be both set"
66+
failed=1
67+
fi
68+
5369
if [ $failed -gt 0 ]; then
5470
exit 1
5571
fi
@@ -62,3 +78,5 @@ echo "Addressing Style: ${S3_STYLE}"
6278
echo "AWS Signatures Version: v${AWS_SIGS_VERSION}"
6379
echo "DNS Resolvers: ${DNS_RESOLVERS}"
6480
echo "Directory Listing Enabled: ${ALLOW_DIRECTORY_LIST}"
81+
echo "Provide Index Pages Enabled: ${PROVIDE_INDEX_PAGE}"
82+
echo "Append slash for directory enabled: ${APPEND_SLASH_FOR_POSSIBLE_DIRECTORY}"

common/etc/nginx/include/s3gateway.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ var fs = require('fs');
3232
*/
3333
var debug = _parseBoolean(process.env['S3_DEBUG']);
3434
var allow_listing = _parseBoolean(process.env['ALLOW_DIRECTORY_LIST'])
35+
var provide_index_page = _parseBoolean(process.env['PROVIDE_INDEX_PAGE'])
36+
var append_slash = _parseBoolean(process.env['APPEND_SLASH_FOR_POSSIBLE_DIRECTORY'])
3537

3638
var s3_style = process.env['S3_STYLE'];
3739

40+
var INDEX_PAGE = "index.html";
41+
3842
/**
3943
* The current moment as a timestamp. This timestamp will be used across
4044
* functions in order for there to be no variations in signatures.
@@ -348,11 +352,14 @@ function s3uri(r) {
348352
if (allow_listing) {
349353
var queryParams = _s3DirQueryParams(uriPath, r.method);
350354
if (queryParams.length > 0) {
351-
path = basePath + '/?' + queryParams;
355+
path = basePath + '?' + queryParams;
352356
} else {
353357
path = basePath + uriPath;
354358
}
355359
} else {
360+
if (provide_index_page && _isDirectory(uriPath) ) {
361+
uriPath += INDEX_PAGE;
362+
}
356363
path = basePath + uriPath;
357364
}
358365

@@ -374,6 +381,11 @@ function _s3DirQueryParams(uriPath, method) {
374381
return '';
375382
}
376383

384+
// return if static website. We don't want to list the files in the directory, we want to append the index page and get the fil.
385+
if (provide_index_page){
386+
return '';
387+
}
388+
377389
let path = 'delimiter=%2F'
378390

379391
if (uriPath !== '/') {
@@ -406,13 +418,25 @@ function redirectToS3(r) {
406418

407419
if (isDirectoryListing && r.method === 'GET') {
408420
r.internalRedirect("@s3Listing");
409-
} else if (!isDirectoryListing && uriPath === '/') {
410-
r.internalRedirect("@error404");
421+
} else if ( provide_index_page == true ) {
422+
r.internalRedirect("@s3");
423+
} else if ( !allow_listing && !provide_index_page && uriPath == "/" ) {
424+
r.internalRedirect("@error404");
411425
} else {
412426
r.internalRedirect("@s3");
413427
}
414428
}
415429

430+
function trailslashControl(r) {
431+
if (append_slash) {
432+
var hasExtension = /\/[^.\/]+\.[^.]+$/;
433+
if (!hasExtension.test(r.variables.uri_path) && !_isDirectory(r.variables.uri_path)){
434+
return r.internalRedirect("@trailslash");
435+
}
436+
}
437+
r.internalRedirect("@error404");
438+
}
439+
416440
/**
417441
* Create HTTP Authorization header for authenticating with an AWS compatible
418442
* v2 API.
@@ -431,6 +455,10 @@ function signatureV2(r, bucket, credentials) {
431455
* nginx, then in S3 we need to request /?delimiter=/&prefix=dir1/
432456
* Thus, we can't put the path /dir1/ in the string to sign. */
433457
var uri = _isDirectory(r.variables.uri_path) ? '/' : r.variables.uri_path;
458+
// To return index pages + index.html
459+
if (provide_index_page && _isDirectory(r.variables.uri_path)){
460+
uri = r.variables.uri_path + INDEX_PAGE
461+
}
434462
var hmac = mod_hmac.createHmac('sha1', credentials.secretAccessKey);
435463
var httpDate = s3date(r);
436464
var stringToSign = method + '\n\n\n' + httpDate + '\n' + '/' + bucket + uri;
@@ -1045,6 +1073,7 @@ export default {
10451073
s3auth,
10461074
s3SecurityToken,
10471075
s3uri,
1076+
trailslashControl,
10481077
redirectToS3,
10491078
editAmzHeaders,
10501079
filterListResponse,

common/etc/nginx/nginx.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ env AWS_SIGS_VERSION;
2020
env S3_DEBUG;
2121
env S3_STYLE;
2222
env ALLOW_DIRECTORY_LIST;
23+
env PROVIDE_INDEX_PAGE;
24+
env APPEND_SLASH_FOR_POSSIBLE_DIRECTORY;
2325
env PROXY_CACHE_VALID_OK;
2426
env PROXY_CACHE_VALID_NOTFOUND;
2527
env PROXY_CACHE_VALID_FORBIDDEN;

common/etc/nginx/templates/default.conf.template

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ server {
112112
proxy_intercept_errors on;
113113

114114
# Comment out this line to receive the error messages returned by S3
115-
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404;
115+
error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 500 501 502 503 504 505 506 507 508 509 510 511 =404 @error404;
116+
117+
error_page 404 @trailslashControl;
116118

117119
proxy_pass ${S3_SERVER_PROTO}://storage_urls$s3uri;
118120
}
@@ -169,6 +171,17 @@ server {
169171
return 404;
170172
}
171173

174+
location @trailslashControl {
175+
# Checks if requesting a folder without trailing slash, and return 302
176+
# appending a slash to it when using for static site hosting.
177+
js_content s3gateway.trailslashControl;
178+
}
179+
180+
location @trailslash {
181+
# 302 to request without slashes
182+
rewrite ^ $scheme://$http_host$request_uri/ redirect;
183+
}
184+
172185
# Provide a hint to the client on 405 errors of the acceptable request methods
173186
error_page 405 @error405;
174187
location @error405 {

docs/getting_started.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
The following environment variables are used to configure the gateway when
1414
running as a Container or as a Systemd service.
1515

16-
* `ALLOW_DIRECTORY_LIST` - Enable directory listing - either true or false
16+
* `ALLOW_DIRECTORY_LIST` - Flag (true/false) enabling directory listing (default: false)
17+
* `PROVIDE_INDEX_PAGE` - Flag (true/false) which returns the index page if there is one when requesting a directory. Cannot be enabled with `ALLOW_DIRECTORY_LIST`. (default: false)
18+
* `APPEND_SLASH_FOR_POSSIBLE_DIRECTORY` - Flag (true/false) enabling the return a 302 with a `/` appended to the path. This is independent of the behavior selected in `ALLOW_DIRECTORY_LIST` or `PROVIDE_INDEX_PAGE`. (default: false)
1719
* `AWS_SIGS_VERSION` - AWS Signatures API version - either 2 or 4
1820
* `DNS_RESOLVERS` - (optional) DNS resolvers (separated by single spaces) to configure NGINX with
1921
* `S3_ACCESS_KEY_ID` - Access key
@@ -78,6 +80,16 @@ result in log messages like:
7880
Another limitation is that when using v2 signatures with HEAD requests, the
7981
gateway will not return 200 for valid folders.
8082

83+
### Static Site Hosting
84+
85+
When `PROVIDE_INDEX_PAGE` environment variable is set to 1, the gateway will
86+
transform `/some/path/` to `/some/path/index.html` when retrieving from S3.
87+
Default of "index.html" can be edited in `s3gateway.js`.
88+
It will also redirect `/some/path` to `/some/path/` when S3 returns 404 on
89+
`/some/path` if `APPEND_SLASH_FOR_POSSIBLE_DIRECTORY` is set. `path` has to
90+
look like a possible directory, it must not start with a `.` and not have an
91+
extension.
92+
8193
## Running as a Systemd Service
8294

8395
A [install script](/standalone_ubuntu_oss_install.sh) for the gateway shows

settings.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ S3_STYLE=virtual
99
S3_DEBUG=false
1010
AWS_SIGS_VERSION=4
1111
ALLOW_DIRECTORY_LIST=false
12+
PROVIDE_INDEX_PAGE=false
13+
APPEND_SLASH_FOR_POSSIBLE_DIRECTORY=false
1214
PROXY_CACHE_VALID_OK=1h
1315
PROXY_CACHE_VALID_NOTFOUND=1m
1416
PROXY_CACHE_VALID_FORBIDDEN=30s

test.sh

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,36 +102,42 @@ if [ "${nginx_type}" = "plus" ]; then
102102
fi
103103

104104
compose() {
105-
${docker_compose_cmd} -f "${test_compose_config}" -p "${test_compose_project}" "$@"
105+
"${docker_compose_cmd}" -f "${test_compose_config}" -p "${test_compose_project}" "$@"
106106
}
107107

108108
integration_test() {
109109
printf "\033[34;1m▶\033[0m"
110110
printf "\e[1m Integration test suite for v%s signatures\e[22m\n" "$1"
111111
printf "\033[34;1m▶\033[0m"
112112
printf "\e[1m Integration test suite with ALLOW_DIRECTORY_LIST=%s\e[22m\n" "$2"
113+
printf "\033[34;1m▶\033[0m"
114+
printf "\e[1m Integration test suite with PROVIDE_INDEX_PAGE=%s\e[22m\n" "$3"
115+
printf "\033[34;1m▶\033[0m"
116+
printf "\e[1m Integration test suite with APPEND_SLASH_FOR_POSSIBLE_DIRECTORY=%s\e[22m\n" "$4"
113117

114118
# See if Minio is already running, if it isn't then we don't need to build it
115-
if [ -z "$(docker ps -q -f name=${test_compose_project}_minio_1)" ]; then
119+
# COMPOSE_COMPATIBILITY=true Supports older style compose filenames with _ vs -
120+
121+
if [ -z "$(docker ps -q -f name=${test_compose_project}_minio-_1)" ]; then
116122
p "Building Docker Compose environment"
117-
AWS_SIGS_VERSION=$1 ALLOW_DIRECTORY_LIST=$2 compose up --no-start
123+
COMPOSE_COMPATIBILITY=true AWS_SIGS_VERSION=$1 ALLOW_DIRECTORY_LIST=$2 PROVIDE_INDEX_PAGE=$3 APPEND_SLASH_FOR_POSSIBLE_DIRECTORY=$4 compose up --no-start
118124

119125
p "Adding test data to container"
120126
echo "Copying contents of ${test_dir}/data to Docker container ${test_compose_project}_minio_1:/"
121-
${docker_cmd} cp "${test_dir}/data" ${test_compose_project}_minio_1:/
127+
"${docker_cmd}" cp "${test_dir}/data" "${test_compose_project}"_minio_1:/
122128
echo "Docker diff output:"
123-
${docker_cmd} diff ${test_compose_project}_minio_1
129+
"${docker_cmd}" diff "${test_compose_project}"_minio_1
124130
fi
125131

126132
p "Starting Docker Compose Environment"
127-
AWS_SIGS_VERSION=$1 ALLOW_DIRECTORY_LIST=$2 compose up -d
133+
COMPOSE_COMPATIBILITY=true AWS_SIGS_VERSION=$1 ALLOW_DIRECTORY_LIST=$2 PROVIDE_INDEX_PAGE=$3 APPEND_SLASH_FOR_POSSIBLE_DIRECTORY=$4 compose up -d
128134

129-
if [ ${wait_for_it_installed} ]; then
135+
if [ "${wait_for_it_installed}" ]; then
130136
# Hit minio's health check end point to see if it has started up
131137
for (( i=1; i<=3; i++ ))
132138
do
133139
echo "Querying minio server to see if it is ready"
134-
minio_is_up="$(${curl_cmd} -s -o /dev/null -w '%{http_code}' ${minio_server}/minio/health/cluster)"
140+
minio_is_up="$(${curl_cmd} -s -o /dev/null -w '%{http_code}' "${minio_server}"/minio/health/cluster)"
135141
if [ "${minio_is_up}" = "200" ]; then
136142
break
137143
else
@@ -140,13 +146,13 @@ integration_test() {
140146
done
141147

142148
if [ -x "${wait_for_it_cmd}" ]; then
143-
$wait_for_it_cmd -h ${nginx_server_host} -p ${nginx_server_port}
149+
"${wait_for_it_cmd}" -h "${nginx_server_host}" -p "${nginx_server_port}"
144150
fi
145151
fi
146152

147153
p "Starting HTTP API tests (v$1 signatures)"
148-
echo " test/integration/test_api.sh \"$test_server\" \"$test_dir\" $1 $2"
149-
bash "${test_dir}/integration/test_api.sh" "$test_server" "$test_dir" "$1" "$2";
154+
echo " test/integration/test_api.sh \"$test_server\" \"$test_dir\" $1 $2 $3 $4"
155+
bash "${test_dir}/integration/test_api.sh" "${test_server}" "${test_dir}" "$1" "$2" "$3" "$4";
150156

151157
# We check to see if NGINX is in fact using the correct version of AWS
152158
# signatures as it was configured to do.
@@ -205,7 +211,9 @@ fi
205211
### UNIT TESTS
206212

207213
p "Running unit tests in Docker image"
208-
${docker_cmd} run \
214+
#MSYS_NO_PATHCONV=1 added to resolve automatic path conversion
215+
# https://github.com/docker/for-win/issues/6754#issuecomment-629702199
216+
MSYS_NO_PATHCONV=1 "${docker_cmd}" run \
209217
--rm \
210218
-v "$(pwd)/test/unit:/var/tmp" \
211219
--workdir /var/tmp \
@@ -225,21 +233,31 @@ ${docker_cmd} run \
225233
### INTEGRATION TESTS
226234

227235
p "Testing API with AWS Signature V2 and allow directory listing off"
228-
integration_test 2 0
236+
integration_test 2 0 0 0
229237

230238
compose stop nginx-s3-gateway # Restart with new config
231239

232240
p "Testing API with AWS Signature V2 and allow directory listing on"
233-
integration_test 2 1
241+
integration_test 2 1 0 0
242+
243+
compose stop nginx-s3-gateway # Restart with new config
244+
245+
p "Testing API with AWS Signature V2 and static site on"
246+
integration_test 2 0 1 0
234247

235248
compose stop nginx-s3-gateway # Restart with new config
236249

237250
p "Test API with AWS Signature V4 and allow directory listing off"
238-
integration_test 4 0
251+
integration_test 4 0 0 0
252+
253+
compose stop nginx-s3-gateway # Restart with new config
254+
255+
p "Test API with AWS Signature V4 and allow directory listing on and appending /"
256+
integration_test 4 1 0 1
239257

240258
compose stop nginx-s3-gateway # Restart with new config
241259

242-
p "Test API with AWS Signature V4 and allow directory listing on"
243-
integration_test 4 1
260+
p "Test API with AWS Signature V4 and static site on appending /"
261+
integration_test 4 0 1 1
244262

245263
p "All integration tests complete"

0 commit comments

Comments
 (0)