UNPKG

s3-autoindex

Version:

Serve the contents of a S3 bucket (private or public) over HTTP

87 lines (84 loc) 2.88 kB
import * as rxme from 'rxme'; import { RxHttpMatcher } from './rx-http'; import { Response } from './rx-http'; import { Config } from './parse-config'; import * as simqle from 'simqle'; import { Subject } from 'rxme'; function loopGetObject(rq: simqle.Queue, rapp: rxme.Subject, s3: AWS.S3, config: Config, mypath: string, res: Response, ofs = 0): rxme.Observable { return rxme.Observable.create(obs => { const bufSize = 1024 * 1024; const lof = { Bucket: config.s3.Bucket, Key: mypath, Range: `bytes=${ofs}-${ofs + bufSize - 1}` }; rapp.next(rxme.LogDebug(`s3.getObject:Request:`, lof)); s3.getObject(lof, (err, data) => { if (err) { res.statusCode = err.statusCode; res.setHeader('X-s3-autoindex', config.version); res.end(); obs.complete(); return; } else { res.statusCode = 200; } rapp.next(rxme.LogDebug(`s3.getObject:Request:data:`, data)); if (ofs == 0) { // bytes 229638144-230686719/584544256 let len = ('' + data.ContentLength); if (data.ContentRange) { len = data.ContentRange.split('/').slice(-1)[0]; } rapp.next(rxme.LogInfo(`fileMatcher:${mypath}:${len}`)); const headers: { [s: string]: string; } = { 'X-s3-autoindex': config.version, 'Content-Length': len, 'Last-Modified': data.LastModified.toUTCString(), 'Expiration': data.Expiration, 'Etag': data.ETag, 'Content-Encoding': data.ContentEncoding, 'Content-Type': data.ContentType, 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET', 'Access-Control-Allow-Headers': 'Host,Content-*', 'Access-Control-Max-Age': '3000' }; for (let k in headers) { if (headers[k]) { res.setHeader(k, headers[k]); } } } res.write(data.Body); if (data.ContentLength < bufSize) { obs.complete(); res.end(); } else { obs.complete(); rq.push(loopGetObject(rq, rapp, s3, config, mypath, res, ofs + bufSize), (new Subject()).passTo()); } }); }); } export default function fileMatcher(rq: simqle.Queue, rapp: rxme.Subject, s3: AWS.S3, config: any): rxme.MatcherCallback { return RxHttpMatcher((remw, sub) => { let mypath = remw.req.url.replace(/\/+/g, '/'); // console.log(`fileMatcher:${mypath}:${remw.req.url}`); if (mypath.startsWith(config.basepath)) { mypath = mypath.substr(config.basepath.length); } if (mypath.endsWith('/')) { // is a not a file return; } if (mypath.startsWith('/')) { mypath = mypath.substr(1); } rq.push(loopGetObject(rq, rapp, s3, config, mypath, remw.res), (new rxme.Subject()).passTo()); }); }