mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-24 03:23:10 +00:00
Add endpoint for arbitrary bucket fetch
Add `/bucket/:bucket/key/*`, which fetches the file from the given bucket at the given path. Uses auth stored at `settings.filestore.s3.{{bucketName}}` if present, and otherwise default auth.
This commit is contained in:
parent
980e1a5d6a
commit
feca8933f1
5 changed files with 145 additions and 5 deletions
|
@ -4,6 +4,7 @@ logger.initialize("filestore")
|
|||
settings = require("settings-sharelatex")
|
||||
request = require("request")
|
||||
fileController = require("./app/js/FileController")
|
||||
bucketController = require("./app/js/BucketController")
|
||||
keyBuilder = require("./app/js/KeyBuilder")
|
||||
healthCheckController = require("./app/js/HealthCheckController")
|
||||
domain = require("domain")
|
||||
|
@ -18,7 +19,7 @@ Metrics.memory.monitor(logger)
|
|||
|
||||
app.configure ->
|
||||
app.use Metrics.http.monitor(logger)
|
||||
|
||||
|
||||
app.configure 'development', ->
|
||||
console.log "Development Enviroment"
|
||||
app.use express.errorHandler({ dumpExceptions: true, showStack: true })
|
||||
|
@ -86,6 +87,8 @@ app.del "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey,
|
|||
|
||||
app.get "/project/:project_id/size", keyBuilder.publicProjectKey, fileController.directorySize
|
||||
|
||||
app.get "/bucket/:bucket/key/*", bucketController.getFile
|
||||
|
||||
app.get "/heapdump", (req, res)->
|
||||
require('heapdump').writeSnapshot '/tmp/' + Date.now() + '.filestore.heapsnapshot', (err, filename)->
|
||||
res.send filename
|
||||
|
@ -103,8 +106,6 @@ app.get '/status', (req, res)->
|
|||
|
||||
|
||||
app.get "/health_check", healthCheckController.check
|
||||
|
||||
|
||||
|
||||
|
||||
app.get '*', (req, res)->
|
||||
|
|
36
services/filestore/app/coffee/BucketController.coffee
Normal file
36
services/filestore/app/coffee/BucketController.coffee
Normal file
|
@ -0,0 +1,36 @@
|
|||
PersistorManager = require("./PersistorManager")
|
||||
settings = require("settings-sharelatex")
|
||||
logger = require("logger-sharelatex")
|
||||
FileHandler = require("./FileHandler")
|
||||
metrics = require("metrics-sharelatex")
|
||||
parseRange = require('range-parser')
|
||||
Errors = require('./Errors')
|
||||
|
||||
oneDayInSeconds = 60 * 60 * 24
|
||||
maxSizeInBytes = 1024 * 1024 * 1024 # 1GB
|
||||
|
||||
module.exports = BucketController =
|
||||
|
||||
getFile: (req, res)->
|
||||
{bucket} = req
|
||||
key = req[0]
|
||||
{format, style} = req.query
|
||||
credentials = settings.filestore.s3&[bucket]
|
||||
options = {
|
||||
key: key,
|
||||
bucket: bucket,
|
||||
credentials: credentials
|
||||
}
|
||||
metrics.inc "getFile"
|
||||
logger.log key:key, bucket:bucket, "receiving request to get file from bucket"
|
||||
FileHandler.getFile bucket, key, options, (err, fileStream)->
|
||||
if err?
|
||||
logger.err err:err, key:key, bucket:bucket, format:format, style:style, "problem getting file from bucket"
|
||||
if err instanceof Errors.NotFoundError
|
||||
return res.send 404
|
||||
else
|
||||
return res.send 500
|
||||
else
|
||||
logger.log key:key, bucket:bucket, format:format, style:style, "sending bucket file to response"
|
||||
fileStream.pipe res
|
||||
|
|
@ -68,8 +68,8 @@ module.exports =
|
|||
callback = _.once callback
|
||||
logger.log bucketName:bucketName, key:key, "getting file from s3"
|
||||
s3Client = knox.createClient
|
||||
key: settings.filestore.s3.key
|
||||
secret: settings.filestore.s3.secret
|
||||
key: opts.credentials?.auth_key || settings.filestore.s3.key
|
||||
secret: opts.credentials?.auth_secret || settings.filestore.s3.secret
|
||||
bucket: bucketName
|
||||
s3Stream = s3Client.get(key, headers)
|
||||
s3Stream.end()
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
assert = require("chai").assert
|
||||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
should = chai.should()
|
||||
expect = chai.expect
|
||||
modulePath = "../../../app/js/BucketController.js"
|
||||
SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe "BucketController", ->
|
||||
|
||||
beforeEach ->
|
||||
@PersistorManager =
|
||||
sendStream: sinon.stub()
|
||||
copyFile: sinon.stub()
|
||||
deleteFile:sinon.stub()
|
||||
|
||||
@settings =
|
||||
s3:
|
||||
buckets:
|
||||
user_files:"user_files"
|
||||
filestore:
|
||||
backend: "s3"
|
||||
s3:
|
||||
secret: "secret"
|
||||
key: "this_key"
|
||||
|
||||
@FileHandler =
|
||||
getFile: sinon.stub()
|
||||
deleteFile: sinon.stub()
|
||||
insertFile: sinon.stub()
|
||||
getDirectorySize: sinon.stub()
|
||||
@LocalFileWriter = {}
|
||||
@controller = SandboxedModule.require modulePath, requires:
|
||||
"./LocalFileWriter":@LocalFileWriter
|
||||
"./FileHandler": @FileHandler
|
||||
"./PersistorManager":@PersistorManager
|
||||
"settings-sharelatex": @settings
|
||||
"logger-sharelatex":
|
||||
log:->
|
||||
err:->
|
||||
@project_id = "project_id"
|
||||
@file_id = "file_id"
|
||||
@bucket = "user_files"
|
||||
@key = "#{@project_id}/#{@file_id}"
|
||||
@req =
|
||||
bucket:@bucket
|
||||
0:@key
|
||||
query:{}
|
||||
headers: {}
|
||||
@res =
|
||||
setHeader: ->
|
||||
@fileStream = {}
|
||||
|
||||
describe "getFile", ->
|
||||
|
||||
it "should pipe the stream", (done)->
|
||||
@FileHandler.getFile.callsArgWith(3, null, @fileStream)
|
||||
@fileStream.pipe = (res)=>
|
||||
res.should.equal @res
|
||||
done()
|
||||
@controller.getFile @req, @res
|
||||
|
||||
it "should send a 500 if there is a problem", (done)->
|
||||
@FileHandler.getFile.callsArgWith(3, "error")
|
||||
@res.send = (code)=>
|
||||
code.should.equal 500
|
||||
done()
|
||||
@controller.getFile @req, @res
|
|
@ -55,6 +55,41 @@ describe "S3PersistorManagerTests", ->
|
|||
@stubbedKnoxClient.get.calledWith(@key).should.equal true
|
||||
done()
|
||||
|
||||
it "should use default auth", (done)->
|
||||
@stubbedKnoxClient.get.returns(
|
||||
on:->
|
||||
end:->
|
||||
)
|
||||
@S3PersistorManager.getFileStream @bucketName, @key, @opts, (err)=> # empty callback
|
||||
clientParams =
|
||||
key: @settings.filestore.s3.key
|
||||
secret: @settings.filestore.s3.secret
|
||||
bucket: @bucketName
|
||||
@knox.createClient.calledWith(clientParams).should.equal true
|
||||
done()
|
||||
|
||||
describe "with supplied auth", ->
|
||||
beforeEach ->
|
||||
@S3PersistorManager = SandboxedModule.require modulePath, requires: @requires
|
||||
@credentials =
|
||||
auth_key: "that_key"
|
||||
auth_secret: "that_secret"
|
||||
@opts =
|
||||
credentials: @credentials
|
||||
|
||||
it "should use supplied auth", (done)->
|
||||
@stubbedKnoxClient.get.returns(
|
||||
on:->
|
||||
end:->
|
||||
)
|
||||
@S3PersistorManager.getFileStream @bucketName, @key, @opts, (err)=> # empty callback
|
||||
clientParams =
|
||||
key: @credentials.auth_key
|
||||
secret: @credentials.auth_secret
|
||||
bucket: @bucketName
|
||||
@knox.createClient.calledWith(clientParams).should.equal true
|
||||
done()
|
||||
|
||||
describe "with start and end options", ->
|
||||
beforeEach ->
|
||||
@opts =
|
||||
|
|
Loading…
Reference in a new issue