mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
rate limit pdf downloads
This commit is contained in:
parent
730088b6ab
commit
cf48c94725
2 changed files with 60 additions and 10 deletions
|
@ -7,6 +7,7 @@ request = require "request"
|
||||||
Settings = require "settings-sharelatex"
|
Settings = require "settings-sharelatex"
|
||||||
AuthenticationController = require "../Authentication/AuthenticationController"
|
AuthenticationController = require "../Authentication/AuthenticationController"
|
||||||
UserGetter = require "../User/UserGetter"
|
UserGetter = require "../User/UserGetter"
|
||||||
|
RateLimiter = require("../../infrastructure/RateLimiter")
|
||||||
|
|
||||||
module.exports = CompileController =
|
module.exports = CompileController =
|
||||||
compile: (req, res, next = (error) ->) ->
|
compile: (req, res, next = (error) ->) ->
|
||||||
|
@ -35,8 +36,11 @@ module.exports = CompileController =
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPdf: (req, res, next = (error) ->)->
|
downloadPdf: (req, res, next = (error) ->)->
|
||||||
|
|
||||||
Metrics.inc "pdf-downloads"
|
Metrics.inc "pdf-downloads"
|
||||||
project_id = req.params.Project_id
|
project_id = req.params.Project_id
|
||||||
|
isPdfjsPartialDownload = req.query?.pdfng
|
||||||
|
|
||||||
Project.findById project_id, {name: 1}, (err, project)->
|
Project.findById project_id, {name: 1}, (err, project)->
|
||||||
res.contentType("application/pdf")
|
res.contentType("application/pdf")
|
||||||
if !!req.query.popupDownload
|
if !!req.query.popupDownload
|
||||||
|
@ -45,6 +49,27 @@ module.exports = CompileController =
|
||||||
else
|
else
|
||||||
logger.log project_id: project_id, "download pdf to embed in browser"
|
logger.log project_id: project_id, "download pdf to embed in browser"
|
||||||
res.header('Content-Disposition', "filename=#{project.getSafeProjectName()}.pdf")
|
res.header('Content-Disposition', "filename=#{project.getSafeProjectName()}.pdf")
|
||||||
|
|
||||||
|
|
||||||
|
if isPdfjsPartialDownload
|
||||||
|
rateLimitOpts =
|
||||||
|
endpointName: "partial-pdf-download"
|
||||||
|
throttle: 500
|
||||||
|
else
|
||||||
|
rateLimitOpts =
|
||||||
|
endpointName: "full-pdf-download"
|
||||||
|
throttle: 50
|
||||||
|
|
||||||
|
rateLimitOpts.subjectName = req.ip
|
||||||
|
rateLimitOpts.timeInterval = 60 * 5
|
||||||
|
RateLimiter.addCount rateLimitOpts, (err, canContinue)->
|
||||||
|
if err?
|
||||||
|
logger.err err:err, "error checking rate limit for pdf download"
|
||||||
|
return res.send 500
|
||||||
|
else if !canContinue
|
||||||
|
logger.log project_id:project_id, ip:req.ip, "rate limit hit downloading pdf"
|
||||||
|
res.send 500
|
||||||
|
else
|
||||||
CompileController.proxyToClsi(project_id, "/project/#{project_id}/output/output.pdf", req, res, next)
|
CompileController.proxyToClsi(project_id, "/project/#{project_id}/output/output.pdf", req, res, next)
|
||||||
|
|
||||||
deleteAuxFiles: (req, res, next) ->
|
deleteAuxFiles: (req, res, next) ->
|
||||||
|
|
|
@ -15,13 +15,15 @@ describe "CompileController", ->
|
||||||
@ClsiManager = {}
|
@ClsiManager = {}
|
||||||
@UserGetter =
|
@UserGetter =
|
||||||
getUser:sinon.stub()
|
getUser:sinon.stub()
|
||||||
@CompileController = SandboxedModule.require modulePath, requires:
|
@RateLimiter = {addCount:sinon.stub()}
|
||||||
"settings-sharelatex": @settings =
|
@settings =
|
||||||
apis:
|
apis:
|
||||||
clsi:
|
clsi:
|
||||||
url: "clsi.example.com"
|
url: "clsi.example.com"
|
||||||
clsi_priority:
|
clsi_priority:
|
||||||
url: "clsi-priority.example.com"
|
url: "clsi-priority.example.com"
|
||||||
|
@CompileController = SandboxedModule.require modulePath, requires:
|
||||||
|
"settings-sharelatex": @settings
|
||||||
"request": @request = sinon.stub()
|
"request": @request = sinon.stub()
|
||||||
"../../models/Project": Project: @Project = {}
|
"../../models/Project": Project: @Project = {}
|
||||||
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
|
||||||
|
@ -30,6 +32,7 @@ describe "CompileController", ->
|
||||||
"../User/UserGetter":@UserGetter
|
"../User/UserGetter":@UserGetter
|
||||||
"./ClsiManager": @ClsiManager
|
"./ClsiManager": @ClsiManager
|
||||||
"../Authentication/AuthenticationController": @AuthenticationController = {}
|
"../Authentication/AuthenticationController": @AuthenticationController = {}
|
||||||
|
"../../infrastructure/RateLimiter":@RateLimiter
|
||||||
@project_id = "project-id"
|
@project_id = "project-id"
|
||||||
@user =
|
@user =
|
||||||
features:
|
features:
|
||||||
|
@ -94,11 +97,13 @@ describe "CompileController", ->
|
||||||
@project =
|
@project =
|
||||||
getSafeProjectName: () => @safe_name = "safe-name"
|
getSafeProjectName: () => @safe_name = "safe-name"
|
||||||
|
|
||||||
|
@req.query = {pdfng:true}
|
||||||
@Project.findById = sinon.stub().callsArgWith(2, null, @project)
|
@Project.findById = sinon.stub().callsArgWith(2, null, @project)
|
||||||
|
|
||||||
describe "when downloading for embedding", ->
|
describe "when downloading for embedding", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@CompileController.proxyToClsi = sinon.stub()
|
@CompileController.proxyToClsi = sinon.stub()
|
||||||
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||||
@CompileController.downloadPdf(@req, @res, @next)
|
@CompileController.downloadPdf(@req, @res, @next)
|
||||||
|
|
||||||
it "should look up the project", ->
|
it "should look up the project", ->
|
||||||
|
@ -122,9 +127,29 @@ describe "CompileController", ->
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should proxy the PDF from the CLSI", ->
|
it "should proxy the PDF from the CLSI", ->
|
||||||
@CompileController.proxyToClsi
|
@CompileController.proxyToClsi.calledWith(@project_id, "/project/#{@project_id}/output/output.pdf", @req, @res, @next).should.equal true
|
||||||
.calledWith(@project_id, "/project/#{@project_id}/output/output.pdf", @req, @res, @next)
|
|
||||||
.should.equal true
|
it "should check the rate limiter", ->
|
||||||
|
@RateLimiter.addCount.args[0][0].throttle.should.equal 500
|
||||||
|
|
||||||
|
describe "when the pdf is not going to be used in pdfjs viewer", ->
|
||||||
|
|
||||||
|
it "should check the rate limiter when pdfng is not set", (done)->
|
||||||
|
@req.query = {}
|
||||||
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||||
|
@CompileController.proxyToClsi = (project_id, url)=>
|
||||||
|
@RateLimiter.addCount.args[0][0].throttle.should.equal 50
|
||||||
|
done()
|
||||||
|
@CompileController.downloadPdf @req, @res
|
||||||
|
|
||||||
|
|
||||||
|
it "should check the rate limiter when pdfng is false", (done)->
|
||||||
|
@req.query = {pdfng:false}
|
||||||
|
@RateLimiter.addCount.callsArgWith(1, null, true)
|
||||||
|
@CompileController.proxyToClsi = (project_id, url)=>
|
||||||
|
@RateLimiter.addCount.args[0][0].throttle.should.equal 50
|
||||||
|
done()
|
||||||
|
@CompileController.downloadPdf @req, @res
|
||||||
|
|
||||||
describe "proxyToClsi", ->
|
describe "proxyToClsi", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
|
Loading…
Reference in a new issue