forked from gmoon/s3proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexpress-s3proxy.js
More file actions
128 lines (111 loc) · 3.85 KB
/
Copy pathexpress-s3proxy.js
File metadata and controls
128 lines (111 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* eslint-disable import/no-extraneous-dependencies, no-console, import/no-unresolved */
/*
S3Proxy Express Framework Example
Passes HTTP GET requests to s3proxy
Start: PORT=3000 node express
Test: mocha test.js
Author: George Moon <george.moon@gmail.com>
*/
const fs = require('fs');
const helmet = require('helmet');
const express = require('express');
const AWSXRay = require('aws-xray-sdk');
const debug = require('debug')('s3proxy');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const addRequestId = require('express-request-id')({ headerName: 'x-request-id' });
const S3Proxy = require('s3proxy');
const port = process.env.PORT;
const bucket = process.env.BUCKET;
const app = express();
app.use(AWSXRay.express.openSegment('s3proxy'));
app.set('view engine', 'pug');
app.use(addRequestId);
app.use(bodyParser.json());
app.use(helmet());
function handleError(req, res, err) {
// sending xml because the AWS SDK sets content-type: application/xml for non-200 responses
res.end(`<?xml version="1.0"?>\n<error time="${err.time}" code="${err.code}" statusCode="${err.statusCode}" url="${req.url}" method="${req.method}">${err.message}</error>
`);
}
// In non-production environments, if a credentials file exists, return the credentials
// To create a temporary credentials file:
// aws sts get-session-token --duration 900 > credentials.json
//
function getCredentials() {
const file = './credentials.json';
var contents = undefined;
try {
const credentials = JSON.parse(fs.readFileSync(file)).Credentials;
if (process.env.NODE_ENV.match(/^prod/i)) {
throw new Error('will not use a credentials file in production');
}
contents = {
accessKeyId: credentials.AccessKeyId,
secretAccessKey: credentials.SecretAccessKey,
sessionToken: credentials.SessionToken
};
debug(`using credentials from ${file}`);
} catch (e) {
debug(`using sdk credential chain`);
}
return contents;
}
// Use morgan for request logging except during test execution
if (process.env.NODE_ENV !== 'test') {
app.use(morgan(
'request :remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] '
+ '":referrer" ":user-agent" ":response-time ms" :res[x-request-id] :res[x-amz-request-id]',
));
}
// initialize the s3proxy
const credentials = getCredentials();
const proxy = new S3Proxy({ bucket, logger: console, credentials });
proxy.init();
proxy.on('error', (err) => {
console.log(`error initializing s3proxy for bucket ${bucket}: ${err.statusCode} ${err.code}`);
});
// basic health check
app.get('/health', (req, res) => {
res.writeHead(200);
res.end();
});
// health check s3
app.get('/health/s3', (req, res) => {
proxy.healthCheckStream(res).on('error', () => {
// just end the request and let the HTTP status code convey the error
res.end();
}).pipe(res);
});
// echo s3proxy version number. You probably want to protect this route as it can expose
// information that could be used for nefarious purposes
app.get('/version', (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(`{"version": "${S3Proxy.version()}"}\n`);
});
// route all get requests to s3proxy
app.get('/', (req, res) => {
res.redirect('/index.html');
});
app.route('/*')
.head(async (req, res) => {
await proxy.head(req, res);
res.end();
})
.get((req, res) => {
proxy.get(req, res).on('error', (err) => {
handleError(req, res, err);
}).pipe(res);
});
app.use(AWSXRay.express.closeSegment());
proxy.on('init', () => {
if (port > 0) {
app.listen(port, () => {
debug(`[version=${S3Proxy.version()}] listening on port ${port}`);
if (process.send) { // test to determine if this is running in a child process
process.send('ready'); // for pm2-runtime wait_ready option
}
});
}
});
module.exports = app;