-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Change request method to a GET
when passing failed requests to config.exceptions_app
#40834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change request method to a GET
when passing failed requests to config.exceptions_app
#40834
Conversation
ac3486b
to
54b8e21
Compare
@eugeneius it'd be awesome to get your review of this, as you're the one who reviewed #40246. |
cd156fd
to
ac1b55f
Compare
Can we do this without adding a new middleware? We try to not grow the list of middleware that the framework includes by default. |
It looks like the |
@rafaelfranca hmm, interesting! What do you think about leveraging |
After a second thought, this is responsibility of the exception app. If it is calling methods that can raise it should know how to deal with the exception. I understand that it does means that you can't pass directly the rails routes as the exception application, but in my opinion this makes sense. The rails routes already raised this same exception and now we are trying to recover from it, if you pass the request to the same application that first raised the exception you should expect the same exception to happen again. What we can do that I think it makes more sense is always use |
@rafaelfranca I was trying to prevent Are you thinking of something like this in request.set_header "action_dispatch.original_request_method", request.raw_request_method
request.request_method = "GET" |
Yes. With that, the original method is stored, so the exception app can use |
…fig.exceptions_app` Similar to rails#38998 (fixed in rails#40246), HTTP method validation occurring whenever methods are called on `ActionDispatch::Request` can cause some weird unintended consequences. For example, if `config.exceptions_app = self.routes`, you get an exception raised via the `ActionDispatch::ShowExceptions` middleware failsafe: ``` Started TEST "/" for 127.0.0.1 at 2020-11-05 15:40:31 -0500 (1.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC TEST, accepted HTTP methods are OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, VERSION-CONTROL, REPORT, CHECKOUT, CHECKIN, UNCHECKOUT, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE-CONTROL, MKACTIVITY, ORDERPATCH, ACL, SEARCH, MKCALENDAR, and PATCH excluded from capture: DSN not set ActionController::UnknownHttpMethod (TEST, accepted HTTP methods are OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, VERSION-CONTROL, REPORT, CHECKOUT, CHECKIN, UNCHECKOUT, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE-CONTROL, MKACTIVITY, ORDERPATCH, ACL, SEARCH, MKCALENDAR, and PATCH): actionpack (6.0.3.4) lib/action_dispatch/http/request.rb:431:in `check_method' actionpack (6.0.3.4) lib/action_dispatch/http/request.rb:143:in `request_method' rack (2.2.3) lib/rack/request.rb:187:in `head?' actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:113:in `find_routes' actionpack (6.0.3.4) lib/action_dispatch/journey/router.rb:32:in `serve' actionpack (6.0.3.4) lib/action_dispatch/routing/route_set.rb:834:in `call' Error during failsafe response: TEST, accepted HTTP methods are OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, VERSION-CONTROL, REPORT, CHECKOUT, CHECKIN, UNCHECKOUT, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE-CONTROL, MKACTIVITY, ORDERPATCH, ACL, SEARCH, MKCALENDAR, and PATCH /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/http/request.rb:431:in `check_method' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/http/request.rb:143:in `request_method' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/request.rb:187:in `head?' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/journey/router.rb:113:in `find_routes' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/journey/router.rb:32:in `serve' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/routing/route_set.rb:834:in `call' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/middleware/show_exceptions.rb:50:in `render_exception' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/middleware/show_exceptions.rb:36:in `rescue in call' /usr/local/var/rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/middleware/show_exceptions.rb:31:in `call' # ... ``` Now, to prevent the redundant exception, we overwrite `request_method` before passing `env` down to `config.exceptions_app`. `action_dispatch.original_request_method` is set to keep the original request method available for inspection.
ac1b55f
to
cb23580
Compare
GET
when passing failed requests to config.exceptions_app
@rafaelfranca thanks for the feedback. Just pushed an update! |
Thanks @rafaelfranca!! Is this something that can/should be backported to |
I don't feel confident on backporting this change to any stable release since this is a change in behavior. I'm not sure if anyone will notice though, so I'll backport to 6-1-stable. 6-0-stable is already in maintenance mode so I don't think it would be good to backport to it. |
Change request method to a `GET` when passing failed requests to `config.exceptions_app`
That makes sense, thanks again! |
I think this change borked my app, we have an API and a web view, and previously a PATCH responding with 404. We have a line in routes.rb that picks up '/404' and sends it to method that redirects to dashboard. So now instead of a 404 it gets changed to What should I do to handle this correctly? |
@jpwhitaker could you show a bit more detail on how to replicate? If a controller responds with a 404 status, I don't think it should go through In terms of how much detail is needed to help fix the bug, I found the replication steps in #43094 super helpful. |
Similar to #38998 (fixed in #40246), HTTP method validation occurring whenever methods are called on
ActionDispatch::Request
can cause some weird unintended consequences. For example, ifconfig.exceptions_app = self.routes
, you get an exception raised via theActionDispatch::ShowExceptions
middleware failsafe:Now, to prevent the redundant exception, we overwrite
request_method
before passingenv
down toconfig.exceptions_app
.action_dispatch.original_request_method
is set to keep the original request method available for inspection.