To ensure Rails is and remains compliant with [the Rack 3 spec](6d16306192/UPGRADE-GUIDE.md) we can add `Rack::Lint` to the Rails middleware tests.
This adds additional test coverage to `ActionDispatch::MiddlewareStack` to validate that its input and output follow the Rack SPEC.
In this case, no changes are required, and the additional test
will ensure this middleware remains compliant with the Rack SPEC.
This adds an additional test to the ActionDispatch::Cookies middleware
test suite to ensure that the middleware sets the expected cookie header
when the request contains a cookie jar. Additionally, the test wraps the
Cookies middleware in Rack::Lint to ensure that ActionDispatch::Cookies
complies with the Rack SPEC.
This adds additional test coverage to ActionableExceptions to validate
that its behavior conforms to the Rack SPEC.
The changes neccesary were to ensure that Response headers are downcased
when using Rack 3. For Content-Type and Content-Length, this is trivial
because Rack provides constants who's casing is dependent on the version
(Rack 2 is mixed, and Rack 3 is downcased). Since Rack does not include
a LOCATION constant, the Response::LOCATION constant was updated to
have a downcased value when using Rack 3.
Additionally, there was some missing coverage for invalid redirect URLs
which was addressed as well.
This adds additional test coverage to HostAuthorization to validate that
its behavior conforms to the Rack SPEC.
By using Rack:: constants for Content-Type and Content-Length, we are
able to use the "correct" versions of the headers for applications using
each Rack version.
Additionally, two tests had to be updated that use an ipv6 address
without brackets in the HOST header because Rack::Lint warned that these
addresses were not valid HOST values. Rack::Lint checks HOST headers using
`URI.parse("http://#{HOST}/")`, and from what I could find, this
requirement follows RFC 3986 Section 3.2.2:
```
host = IP-literal / IPv4address / reg-name
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
```
To ensure Rails is and remains compliant with [the Rack 3
spec](6d16306192/UPGRADE-GUIDE.md)
we can add `Rack::Lint` to the Rails middleware tests.
There was no test file for ActionDispatch::AssumeSSL, so this change
adds one and validating that its input and output follow the Rack SPEC.
When development tools try to load Rails components, they sometimes end up loading files that will error out since a dependency is missing. In these cases, the tooling can catch the error and change its behaviour.
However, since the warning is printed directly to `$stderr`, the tooling cannot catch and suppress it easily, which ends up causing noise in the output of the tool.
This change makes Rails print these warnings using `Kernel#warn` instead, which can be suppressed by the tooling.
The set of legal characters for an HTTP header value is described
in https://datatracker.ietf.org/doc/html/rfc7230\#section-3.2.6.
This commit adds a check to redirect_to that ensures the
provided URL does not contain any of the illegal characters.
Downstream consumers of the resulting Location response header
may accidentally remove the header if it does not comply with the RFC
resulting in unexpected behavior.
Related to [CVE-2023-28362].
This middleware has been logging at a FATAL level since the first
[commit][1] in Rails (the code originally lived in
actionpack/lib/action_controller/rescue.rb). However, FATAL is
documented in the Ruby Logger [docs][2] as being for "An unhandleable
error that results in a program crash.", which does not really apply to
this case since DebugExceptions is handling the error. A more
appropriate level would be ERROR, which the Ruby Logger docs describe as
"A handleable error condition."
This commit introduces a new configuration for the DebugExceptions log
level so that new apps will have it set to ERROR by default and ERROR
can eventually be made the default.
[1]: db045dbbf60b53dbe013ef25554fd013baf88134
[2]: https://ruby-doc.org/3.2.1/stdlibs/logger/Logger/Severity.html
For local environments (def and test), we create a secret file. However this file is called development_secret.txt, which imho is confusing as it is used by both dev and test environments.
This commit renames the file and related code to local_secret.
* Unlink the Rails module automatically
* Inline the documentation links for unicorn and passenger
* Use RDoc fixed-width for passenger_buffer_response instead of markdown
* TIL: about linking to headings, so fixed that for "Middlewares" section
RackBody is the final body object returned by the Rack app
(`Rails.application`). This test that it conforms to the spec
instead of testing on the underlying response.
ActionDispatch::Response delegates #to_ary to the internal ActionDispatch::Response::Buffer,
defining #to_ary is an indicator that the response body can be buffered and/or cached by
Rack middlewares, this is not the case for Live responses so we undefine it for this Buffer subclass.
Puma raises an exception trying to call #to_ary in Live::Buffer
expecting it to return an array if defined:
188f5da192/lib/puma/request.rb (L183-L186)
The rack spec requires the header object to be an unfrozen hash.
c8e9822183/SPEC.rdoc (L240)
Rack::ETag was buffering and making a copy of the response,
so the freeze was not effective anyway.
Plus we are freezing the hash too early, preventing middlewares
from modifying it. It causes crash with gems like rack-livereload.
I started having crashes on some pages (like the internal
http://localhost:3000/rails/info/routes) because of rack-livereload
hitting the frozen hash after the rack 3 upgrade.
Also we're not consistent with the protection. We're not preventing
users from adding cookies. The cookie jar is already flushed,
therefore it doesn't try to change the headers and never triggers the
frozen hash error.
Previously, `ActionDispatch::Static` would always merge a "content-type"
header into the headers returned from `Rack::Files`. However, this would
potentially lead to both a "Content-Type" header and a "content-type"
header when using Rack 2.
This commit fixes the issue by using `Rack::CONTENT_TYPE` to determine
which version of the header to set in `ActionDispatch::Static`. In both
versions of Rack it will use the same version of the header as
`Rack::Files`.
The tests added have to use `@app.call` instead of
`get()`/`Rack::MockRequest` because `Rack::Response` actually does the
correct thing already by using `Rack::Util::HeaderHash` so it covers up
the issue in tests.
Turbo frames on turbo-rails 1.4 (current default in Rails 7) don't
break out of the frame to load the error response from the DebugView
middleware like they used to. It requires the turbo-visit-control meta set to reload or it
fails silently.
Accept headers allow parameters to be passed. They can contain quotes
that need to be handled differently. These quoted strings can contain
commas, which are not considered as delimiters of accept headers.
Additionally, all parameters before the q-parameter should be used to
lookup the media-type as well. If no media-type with the parameters is
found, a fallback is introduced to the media-type without any parameters
to keep the same functionality as before.
Fix#48052
The `cookies` method was not defined on ActionController::Base making the
permalink to the method not work.
Changing it to ActionController::Cookies make the reference a link.
The url_for helper now supports a new option called `bind_params`.
This is very useful in situations where you only want to add a required
param that is part of the route's URL but for other route not append an
extraneous query param.
Given the following router...
```ruby
Rails.application.routes.draw do
scope ":account_id" do
get 'dashboard' => 'pages#dashboard', as: :dashboard
get 'search/:term' => 'search#search', as: :search
end
delete 'signout' => 'sessions#destroy', as: :signout
end
```
And given the following `ApplicationController`
```ruby
class ApplicationController < ActionController::Base
def default_url_options
{ bind_params: { account_id: "foo" } }
end
end
```
The standard URLHelpers will now behave as follows:
```ruby
dashboard_path # => /foo/dashboard
dashboard_path(account_id: "bar") # => /bar/dashboard
signout_path # => /signout
signout_path(account_id: "bar") # => /signout?account_id=bar
search_path("quin") # => /foo/search/quin
```