Merge pull request #8729 from overleaf/bg-return-file-too-large

[document-updater] return 413 error when doc is too large

GitOrigin-RevId: d66300c78bea4071f29044be160929dba782b728
This commit is contained in:
Brian Gough 2022-07-06 10:50:16 +01:00 committed by Copybot
parent 768a5a7d0f
commit 0c63515de6
4 changed files with 78 additions and 0 deletions

View file

@ -185,6 +185,8 @@ app.use((error, req, res, next) => {
return res.sendStatus(404) return res.sendStatus(404)
} else if (error instanceof Errors.OpRangeNotAvailableError) { } else if (error instanceof Errors.OpRangeNotAvailableError) {
return res.sendStatus(422) // Unprocessable Entity return res.sendStatus(422) // Unprocessable Entity
} else if (error instanceof Errors.FileTooLargeError) {
return res.sendStatus(413)
} else if (error.statusCode === 413) { } else if (error.statusCode === 413) {
return res.status(413).send('request entity too large') return res.status(413).send('request entity too large')
} else { } else {

View file

@ -37,9 +37,18 @@ function DeleteMismatchError(message) {
} }
DeleteMismatchError.prototype.__proto__ = Error.prototype DeleteMismatchError.prototype.__proto__ = Error.prototype
function FileTooLargeError(message) {
const error = new Error(message)
error.name = 'FileTooLargeError'
error.__proto__ = FileTooLargeError.prototype
return error
}
FileTooLargeError.prototype.__proto__ = Error.prototype
module.exports = Errors = { module.exports = Errors = {
NotFoundError, NotFoundError,
OpRangeNotAvailableError, OpRangeNotAvailableError,
ProjectStateChangedError, ProjectStateChangedError,
DeleteMismatchError, DeleteMismatchError,
FileTooLargeError,
} }

View file

@ -104,6 +104,10 @@ function getDoc(projectId, docId, options = {}, _callback) {
) )
} else if (res.statusCode === 404) { } else if (res.statusCode === 404) {
callback(new Errors.NotFoundError(`doc not not found: ${urlPath}`)) callback(new Errors.NotFoundError(`doc not not found: ${urlPath}`))
} else if (res.statusCode === 413) {
callback(
new Errors.FileTooLargeError(`doc exceeds maximum size: ${urlPath}`)
)
} else { } else {
callback( callback(
new Error(`error accessing web API: ${urlPath} ${res.statusCode}`) new Error(`error accessing web API: ${urlPath} ${res.statusCode}`)
@ -158,6 +162,10 @@ function setDoc(
callback(null) callback(null)
} else if (res.statusCode === 404) { } else if (res.statusCode === 404) {
callback(new Errors.NotFoundError(`doc not not found: ${urlPath}`)) callback(new Errors.NotFoundError(`doc not not found: ${urlPath}`))
} else if (res.statusCode === 413) {
callback(
new Errors.FileTooLargeError(`doc exceeds maximum size: ${urlPath}`)
)
} else { } else {
callback( callback(
new Error(`error accessing web API: ${urlPath} ${res.statusCode}`) new Error(`error accessing web API: ${urlPath} ${res.statusCode}`)

View file

@ -206,6 +206,33 @@ describe('PersistenceManager', function () {
}) })
}) })
describe('when the request returns 413', function () {
beforeEach(function () {
this.request.callsArgWith(1, null, { statusCode: 413 }, '')
this.PersistenceManager.getDoc(
this.project_id,
this.doc_id,
this.callback
)
})
it('should return a FileTooLargeError', function () {
this.callback
.calledWith(sinon.match.instanceOf(Errors.FileTooLargeError))
.should.equal(true)
})
it('should time the execution', function () {
this.Metrics.Timer.prototype.done.called.should.equal(true)
})
it('should increment the metric', function () {
this.Metrics.inc
.calledWith('getDoc', 1, { status: 413 })
.should.equal(true)
})
})
describe('when the request returns an error status code', function () { describe('when the request returns an error status code', function () {
beforeEach(function () { beforeEach(function () {
this.request.callsArgWith(1, null, { statusCode: 500 }, '') this.request.callsArgWith(1, null, { statusCode: 500 }, '')
@ -427,6 +454,38 @@ describe('PersistenceManager', function () {
}) })
}) })
describe('when the request returns 413', function () {
beforeEach(function () {
this.request.callsArgWith(1, null, { statusCode: 413 }, '')
this.PersistenceManager.setDoc(
this.project_id,
this.doc_id,
this.lines,
this.version,
this.ranges,
this.lastUpdatedAt,
this.lastUpdatedBy,
this.callback
)
})
it('should return a FileTooLargeError', function () {
this.callback
.calledWith(sinon.match.instanceOf(Errors.FileTooLargeError))
.should.equal(true)
})
it('should time the execution', function () {
this.Metrics.Timer.prototype.done.called.should.equal(true)
})
it('should increment the metric', function () {
this.Metrics.inc
.calledWith('setDoc', 1, { status: 413 })
.should.equal(true)
})
})
describe('when the request returns an error status code', function () { describe('when the request returns an error status code', function () {
beforeEach(function () { beforeEach(function () {
this.request.callsArgWith(1, null, { statusCode: 500 }, '') this.request.callsArgWith(1, null, { statusCode: 500 }, '')