Skip to content

Instantly share code, notes, and snippets.

@askldjd
Last active May 4, 2017 22:40
Show Gist options
  • Save askldjd/ca98b949729fce5d9cc251b3d91a7d8e to your computer and use it in GitHub Desktop.
Save askldjd/ca98b949729fce5d9cc251b3d91a7d8e to your computer and use it in GitHub Desktop.
Node.js S3 Streamer for Efolder Express
// This Express server is designed to support Efolder-Express Rails server to
// allow streaming data from S3 without first saving a local copy on disk.
const express = require('express')
const app = express()
const AWS = require('aws-sdk');
AWS
.config
.update({region: 'us-gov-west-1'});
const s3 = new AWS.S3();
app.use(require('cookie-parser')());
const sessionDecoder = require('rails-session-decoder');
// Use the shared SECRET_KEY_BASE from the env file to setup the Rails session
// decoder.
const decoder = sessionDecoder(process.env.SECRET_KEY_BASE);
const sessionCookieName = '_caseflow_session';
// Setup a middleware to decode the Rails session cookie. Whenever "_caseflow_session"
// is present, it will be decoded.
app.use(function (req, res, next) {
if (req.cookies && req.cookies[sessionCookieName]) {
decoder
.decodeCookie(req.cookies[sessionCookieName], function (err, sessionData) {
req.cookies[sessionCookieName] = JSON.parse(sessionData);
next(err);
});
} else {
next();
}
});
// stream-download re-check user's authority from its session, and pipe
// the request directly to S3 if the user is authorized for this download.
app.get('/stream-download/:filename', function (req, res) {
const session = req.cookies[sessionCookieName];
if (!session || !session.user || !session.user.roles || session.user.roles.indexOf('Download efolder') != -1) {
return res
.status(403)
.send('not authorized');
}
s3
.getObject({Bucket: process.env.AWS_BUCKET_NAME, Key: req.params.filename })
.on('httpHeaders', function (statusCode, headers) {
res.set('Content-Length', headers['content-length']);
res.set('Content-Type', headers['content-type']);
this
.response
.httpResponse
.createUnbufferedStream()
.pipe(res);
})
.send();
})
// Nginx is expected to proxy /stream-download to port 3002.
app.listen(3002, function () {
console.log('listening on 3002')
})
# Nginx config changes to re-route /stream-download/ path to Node.js
# streaming server
# streamer is on 3002, but this is arbitrary
upstream streamer_app {
server 127.0.0.1:3002;
}
# Any URL with /assets should be served by Nginx.
location ^~ /stream-download/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
# Disable disk cache to allow large files to be downloaded.
# See https://serverfault.com/questions/820597/nginx-does-not-serve-large-files
proxy_max_temp_file_size 0;
proxy_pass http://streamer_app;
}
{
"name": "node-proxy-s3",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"aws-sdk": "^2.48.0",
"cookie-parser": "^1.4.3",
"express": "^4.15.2",
"rails-cookie-parser": "0.0.3",
"rails-session-decoder": "^1.0.4"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment