Files
ubicloud/helpers/web.rb
Jeremy Evans da721d6c9c Change error handling from redirecting to using an internal request
This changes redirect_back_with_inputs to use an internal request instead
of redirecting back.  The main advantage from doing this is you do not
need to store the submitted parameters in the flash, which avoids overflowing
the session (CookieTooLarge errors) and avoids JSON::GeneratorError if the
submitted inputs contain invalid UTF-8.

The internal requests use the rack API to Clover, so they appear to Clover
to be new GET requests from the server, for the referring page.  We rotate
the flash before the internal request, matching the previous redirect
behavior.

This changes some requests that result in error pages to use 400 responses
instead of 200 responses.  The 200 responses are not accurate, since the
request was a failure and not a success, they were an artifact of the
redirect implementation.  Other than this behavior improvement, there are
no changes to the specs, except for one new spec for a corner case (bad
Referer header value).

Note that redirects are still used inside of internal requests if the
original request is a GET request.  This is done to prevent internal
request loops, but the issue we are trying to avoid is not a significant
issue for GET requests, so it seems fine to limit it to non-GET requests.

For invalid or missing referer values, this redirects back to the root,
with no setting of old values.  The old values wouldn't be helpful for a
root request anyway.

We discard the flash after making the internal request, so the flash
message does not show up on the next page request.

The `flash["referrer"] = referrer` code is used to handle the following
case:

* User goes to path X
* User submits form to path Y
* Results in error, redisplaying form shown on path X, but browser
  referer is now Y and not X
* User resubmit form
* Which has the same or other error, and we want to redisplay form shown
  on path X, not on path Y

We may want to consider changing redirect_back_with_inputs to a different
name, now that the standard implementation does an internal request. But
that can be done later.
2024-12-02 09:35:14 -08:00

34 lines
881 B
Ruby

# frozen_string_literal: true
class Clover < Roda
def csrf_tag(*)
render("components/form/hidden", locals: {name: csrf_field, value: csrf_token(*)})
end
def redirect_back_with_inputs
referrer = flash["referrer"] || env["HTTP_REFERER"]
uri = begin
Kernel.URI(referrer)
rescue URI::InvalidURIError, ArgumentError
nil
end
request.redirect "/" unless uri
flash["old"] = request.params
if uri && env["REQUEST_METHOD"] != "GET"
# Force flash rotation, so flash works correctly for internal redirects
_roda_after_40__flash(nil)
rack_response = Clover.call(env.merge("REQUEST_METHOD" => "GET", "PATH_INFO" => uri.path))
flash.discard
flash["referrer"] = referrer
rack_response[0] = response.status || 400
request.halt rack_response
else
request.redirect referrer
end
end
end