Files
Verso/services/web/app/src/Features/Errors/HttpErrorHandler.js
T
Jakob Ackermann 73ae6f480f [web] change status page URL to HTTPS everywhere (#26587)
* [web] change status page URL to HTTPS everywhere

Also open all links to the status page or admin email in a new tab.

* [server-ce] explicit protocol matching

Co-authored-by: Brian Gough <brian.gough@overleaf.com>

---------

Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: d7d12eef4efc737c5d70fc969c862acae9faf14c
2025-06-26 08:04:59 +00:00

161 lines
4.5 KiB
JavaScript

const logger = require('@overleaf/logger')
const Settings = require('@overleaf/settings')
const { plainTextResponse } = require('../../infrastructure/Response')
function renderJSONError(res, message, info = {}) {
if (info.message) {
logger.warn(
info,
`http error info shouldn't contain a 'message' field, will be overridden`
)
}
if (message != null) {
res.json({ ...info, message })
} else {
res.json(info)
}
}
function handleGeneric500Error(req, res, statusCode, message) {
res.status(statusCode)
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('general/500', { title: 'Server Error' })
case 'json':
return renderJSONError(res, message)
default:
return plainTextResponse(res, 'internal server error')
}
}
function handleGeneric400Error(req, res, statusCode, message, info = {}) {
res.status(statusCode)
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('general/400', {
title: 'Client Error',
message,
})
case 'json':
return renderJSONError(res, message, info)
default:
return plainTextResponse(res, 'client error')
}
}
let HttpErrorHandler
module.exports = HttpErrorHandler = {
handleErrorByStatusCode(req, res, err, statusCode) {
const is400Error = statusCode >= 400 && statusCode < 500
const is500Error = statusCode >= 500 && statusCode < 600
req.logger.addFields({ err })
if (is400Error) {
req.logger.setLevel('warn')
} else if (is500Error) {
req.logger.setLevel('error')
}
if (statusCode === 403) {
HttpErrorHandler.forbidden(req, res)
} else if (statusCode === 404) {
HttpErrorHandler.notFound(req, res)
} else if (statusCode === 409) {
HttpErrorHandler.conflict(req, res, '')
} else if (statusCode === 422) {
HttpErrorHandler.unprocessableEntity(req, res)
} else if (is400Error) {
handleGeneric400Error(req, res, statusCode)
} else if (is500Error) {
handleGeneric500Error(req, res, statusCode)
} else {
res.sendStatus(500)
}
},
badRequest(req, res, message, info = {}) {
handleGeneric400Error(req, res, 400, message, info)
},
conflict(req, res, message, info = {}) {
res.status(409)
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('general/400', {
title: 'Client Error',
message,
})
case 'json':
return renderJSONError(res, message, info)
default:
return plainTextResponse(res, 'conflict')
}
},
forbidden(req, res, message = 'restricted', info = {}) {
res.status(403)
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('user/restricted', { title: 'restricted' })
case 'json':
return renderJSONError(res, message, info)
default:
return plainTextResponse(res, 'restricted')
}
},
notFound(req, res, message = 'not found', info = {}) {
res.status(404)
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('general/404', { title: 'page_not_found' })
case 'json':
return renderJSONError(res, message, info)
default:
return plainTextResponse(res, 'not found')
}
},
unprocessableEntity(req, res, message = 'unprocessable entity', info = {}) {
res.status(422)
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('general/400', {
title: 'Client Error',
message,
})
case 'json':
return renderJSONError(res, message, info)
default:
return plainTextResponse(res, 'unprocessable entity')
}
},
legacyInternal(req, res, message, err) {
req.logger.addFields({ err })
req.logger.setLevel('error')
handleGeneric500Error(req, res, 500, message)
},
maintenance(req, res) {
// load balancer health checks require a success response for /
if (req.url === '/') {
res.status(200)
} else {
res.status(503)
}
let message = `${Settings.appName} is currently down for maintenance.`
if (Settings.statusPageUrl) {
message += ` Please check ${Settings.statusPageUrl} for updates.`
}
switch (req.accepts(['html', 'json'])) {
case 'html':
return res.render('general/closed', { title: 'maintenance' })
case 'json':
return renderJSONError(res, message, {})
default:
return plainTextResponse(res, message)
}
},
}