2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-01-12 11:15:10 +08:00
|
|
|
# since all the rescue from clauses are not caught by the application controller for matches
|
|
|
|
# we need to handle certain exceptions here
|
|
|
|
module Middleware
|
|
|
|
class DiscoursePublicExceptions < ::ActionDispatch::PublicExceptions
|
2024-04-24 16:40:13 +08:00
|
|
|
# These middlewares will be re-run when the exception response is generated
|
|
|
|
EXCEPTION_RESPONSE_MIDDLEWARES = [
|
|
|
|
ContentSecurityPolicy::Middleware,
|
|
|
|
Middleware::CspScriptNonceInjector,
|
|
|
|
]
|
|
|
|
|
2022-02-07 21:16:57 +08:00
|
|
|
INVALID_REQUEST_ERRORS =
|
|
|
|
Set.new(
|
|
|
|
[
|
|
|
|
Rack::QueryParser::InvalidParameterError,
|
|
|
|
ActionController::BadRequest,
|
|
|
|
ActionDispatch::Http::Parameters::ParseError,
|
2023-03-10 17:17:59 +08:00
|
|
|
ActionController::RoutingError,
|
2022-02-07 21:16:57 +08:00
|
|
|
],
|
|
|
|
)
|
2018-01-12 11:15:10 +08:00
|
|
|
|
|
|
|
def call(env)
|
|
|
|
# this is so so gnarly
|
|
|
|
# sometimes we leak out exceptions prior to creating a controller instance
|
|
|
|
# this can happen if we have an exception in a route constraint in some cases
|
|
|
|
# this code re-dispatches the exception to our application controller so we can
|
|
|
|
# properly translate the exception to a page
|
|
|
|
exception = env["action_dispatch.exception"]
|
|
|
|
response = ActionDispatch::Response.new
|
|
|
|
|
2022-02-07 21:16:57 +08:00
|
|
|
exception = nil if INVALID_REQUEST_ERRORS.include?(exception)
|
2018-12-13 15:27:02 +08:00
|
|
|
|
2018-01-12 11:15:10 +08:00
|
|
|
if exception
|
2018-01-23 06:00:08 +08:00
|
|
|
begin
|
|
|
|
fake_controller = ApplicationController.new
|
2024-06-27 00:55:05 +08:00
|
|
|
fake_controller.response = response
|
2019-11-21 12:51:18 +08:00
|
|
|
fake_controller.request = request = ActionDispatch::Request.new(env)
|
|
|
|
|
2020-01-02 09:34:38 +08:00
|
|
|
# We can not re-dispatch bad mime types
|
2019-11-21 12:51:18 +08:00
|
|
|
begin
|
|
|
|
request.format
|
|
|
|
rescue Mime::Type::InvalidMimeType
|
2021-11-13 02:52:25 +08:00
|
|
|
return [
|
|
|
|
400,
|
|
|
|
{ "Cache-Control" => "private, max-age=0, must-revalidate" },
|
|
|
|
["Invalid MIME type"]
|
2023-01-09 20:10:19 +08:00
|
|
|
]
|
2019-11-21 12:51:18 +08:00
|
|
|
end
|
2018-01-12 11:15:10 +08:00
|
|
|
|
2022-02-07 21:16:57 +08:00
|
|
|
# Or badly formatted multipart requests
|
|
|
|
begin
|
|
|
|
request.POST
|
2023-06-28 08:17:11 +08:00
|
|
|
rescue ActionController::BadRequest => error
|
|
|
|
if error.cause.is_a?(EOFError)
|
|
|
|
return [
|
|
|
|
400,
|
|
|
|
{ "Cache-Control" => "private, max-age=0, must-revalidate" },
|
|
|
|
["Invalid request"]
|
|
|
|
]
|
|
|
|
else
|
|
|
|
raise
|
|
|
|
end
|
2022-02-07 21:16:57 +08:00
|
|
|
end
|
|
|
|
|
2018-01-23 06:00:08 +08:00
|
|
|
if ApplicationController.rescue_with_handler(exception, object: fake_controller)
|
|
|
|
body = response.body
|
|
|
|
body = [body] if String === body
|
2024-04-24 16:40:13 +08:00
|
|
|
rack_response = [response.status, response.headers, body]
|
|
|
|
app = lambda { |env| rack_response }
|
|
|
|
EXCEPTION_RESPONSE_MIDDLEWARES.each { |middleware| app = middleware.new(app) }
|
|
|
|
return app.call(env)
|
2018-01-23 06:00:08 +08:00
|
|
|
end
|
|
|
|
rescue => e
|
2022-02-07 21:16:57 +08:00
|
|
|
return super if INVALID_REQUEST_ERRORS.include?(e.class)
|
2018-01-23 06:00:08 +08:00
|
|
|
Discourse.warn_exception(
|
|
|
|
e,
|
|
|
|
message: "Failed to handle exception in exception app middleware",
|
|
|
|
)
|
2018-01-12 11:15:10 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
super
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|