Rails has incorrectly been adding leading dots to cookie domain values
when the `domain: :all` option is present.
This leading dot was required in cookies based on [RFC 2965][rfc2965]
(October 2000), but [RFC 6265][rfc6265] (April 2011) changed that
behaviour, making a leading dot strictly incorrect. Todays browsers aim
to confirm to RFC6265 with repect to cookies.
The new behaviour is that *any* cookie with an explicitly passed domain
is sent to all matching subdomains[[ref][mdn]]. For a server to indicate
that only the exact origin server should receive the cookie, it should
instead pass *no* domain attribute.
Despite the change in behaviour, browser devtools often display a cookie
domain with a leading dot to indicate that it is valid for subdomains -
this prefixed domain is *not* necessarily the raw value that was passed
in the Set-Cookie header. This explains why it's a common belief among
developers that the leading dot is required.
RFC6265 standard gives UAs an algorithm to handle old-style cookie
domain parameters (they can drop a leading dot if present), so it's
unlikely that this error would ever have had any effect on web browsers.
However, cookies generated this way can't be processed by Ruby's own
CGI::Cookie class:
> CGI::Cookie.new "domain" => ".foo.bar", "name" => "foo"
ArgumentError: invalid domain: ".foo.bar"
Newer versions of the Ruby CGI library accomodate the same fallback
behaviour (dropping the extra dot) but this isn't a justification for it
being the right way to set a cookie.
[mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#domain_attribute
[rfc2965]: https://www.rfc-editor.org/rfc/rfc2965#section-3.2
[rfc6265]: https://www.rfc-editor.org/rfc/rfc6265#section-4.1.1
In larger route files, or when routes are spread across multiple files,
it can be difficult to get from the output of the route inspector to the
relevant route definition.
This commit adds a route source location to the route, and uses that in
the HtmlTableFormatter (for rails/info and the debug exceptions
middleware) and the Expanded formatter (for `rails routes -E`).
To avoid doing extra work in production, it only sets the source location
in development.
This commit injects the application's backtrace cleaner so we can use it
to remove the rails root from the path. This also means we don't get
source locations for the routes defined by Rails.
If mounting an engine from a gem, we'll get a source location for where
we mount it in the application, but not for the routes defined in the
gem itself. That's probably good enough, since Rails already prints
routes for an engine separately under the title "Routes for
Foo::Engine".
Co-authored-by: John Hawthorn <jhawthorn@github.com>
Co-authored-by: Luan Vieira <luanzeba@github.com>
Co-authored-by: Daniel Colson <composerinteralia@github.com>
Since rails/rails#47296, nothing sets the fullpath early, so changing
the path of a request, and then calling original_fullpath returns the
updated fullpath. This is a controller testing specific bug as
integration tests and real requests always have this header set, so I
think controller tests should too.
Previously, ActionDispatch::IllegalStateError was deprecated using
Module#deprecate_constant in 0b4b4c6b96a41ef649f15e1a3df26e28ef95ff24.
This requires the -w flag to be used to actually see the deprecation
warning, and it can not be controlled using ActiveSupport::Deprecator
configuration.
This commit changes the deprecation to use #deprecate_constant from
ActiveSupport::Deprecation::DeprecatedConstantAccessor. This ensures
that the deprecation warning will be printed even without -w, and the
warning can be controlled by configuring ActionDispatch.deprecator
This error used to be a wrapper for a LoadError raised when
require_dependency was used to load helpers for controllers.
Since Zeitwerk does not use require_dependency, the only usage of the
error was removed in 5b28a0e972da31da570ed24be505ef7958ab4b5e.
Prior to this commit, the only out-of-the-box parsing that
`ActionDispatch::Testing::TestResponse#parsed_body` supported was for
`application/json` requests. This meant that `response.body ==
response.parsed_body` for HTML requests.
```ruby
get "/posts"
response.content_type # => "text/html; charset=utf-8"
response.parsed_body.class # => Nokogiri::HTML5::Document
response.parsed_body.to_html # => "<!DOCTYPE html>\n<html>\n..."
```
Using `parsed_body` for JSON requests supports `Hash#fetch`, `Hash#dig`,
and Ruby 3.2 destructuring assignment and pattern matching.
The introduction of [Nokogiri support for pattern
matching][nokogiri-pattern-matching] poses an opportunity to make assertions
about the structure of the HTML response.
On top of that, there is ongoing work to [introduce pattern matching
support in MiniTest][minitest-pattern-matching].
[nokogiri-pattern-matching]: https://github.com/sparklemotion/nokogiri/pull/2523
[minitest-pattern-matching]: https://github.com/minitest/minitest/pull/936
In the GitHub RoR monolith, we output the route URI pattern
in an HTML meta tag in our application layout for analysis
purposes. However, our current implementation is quite manual.
This change adds an attribute to requests with the URI pattern
of the matched route.
Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
Co-authored-by: Kate Higa <khiga8@github.com>
Rack 3 introduces streaming bodies, which don't respond to `#each` and
MUST respond to `#call`. Ensure that the methods are correctly delegated.
`#to_ary` must also work correctly for enumerable bodies, and is used by
middleware like `Rack::ETag` to buffer enumerable bodies correctly.
Rack 3 response headers must be a mutable hash with lower-case keys. Rack
provides `Rack::Headers` as a compatibility layer for existing systems
which don't conform to this requirement. Prefer `Rack::Utils::HeaderHash`
on Rack 2, and `Rack::Headers` on Rack 3.
Remove some of the response test cases which test `nil` header keys as
these are considered invalid, and will fail with `Rack::Headers`.
The current implementation makes assumptions about the case and format of
headers. Introduce methods to handle headers in a case insensitive manner
and reduce churn when comparing with multi-value headers.
The current implementation makes assumptions about the order and case
sensitivity of cookie attributes. Introduce methods to parse those fields
and compare them semantically. Update the existing tests to take advantage
of these new assertions.
Previously, ActionDispatch::IntegrationTest would always set
CONTENT_TYPE on the request whether or not the value being set was a
string or nil. However, Rack SPEC requires that if CONTENT_TYPE is set,
it must be a string.
Since the request_encoder can return nil for #content_type (and the
IdentityEncoder always will), IntegrationTest must check before it sets
the CONTENT_TYPE value.
A Rack::Lint test has been added to prevent regressions. Additionally,
it will make changes needed for Rack 3 more obvious when the time comes.