In our recent optimizations to route matching performance we introduced
an issue with routes that had an optional segment which wasn't separated
by a "." or "/".
When using `Pathname#relative_path_from`, the receiver and the argument
must either both be absolute or both be relative:
https://ruby-doc.org/stdlib-2.7.2/libdoc/pathname/rdoc/Pathname.html#method-i-relative_path_from
> If self is absolute, then base_directory must be absolute too.
>
> If self is relative, then base_directory must be relative too.
If `file_fixture_path` is a relative path and `fixture_path` is an
absolute path, this line would previously raise an ArgumentError.
The FSM used to find matching routes was previously limited to patterns
that contained parameters with the default regexp / no constraints. In
large route sets where many parameters are constrained by custom regexp,
these routes all fall back on a slow linear search over the route list.
These custom regexes were not previously able to be included in the FSM
because it transitioned between nodes using only fragments of the URI,
or path separators [/.?], but a custom regex may cross a path separator
boundary. To work around this, the TransitionTable is improved to
support remembering a point within the matching string that we started,
and continuing to attempt to match from that point up to the end of each
token. Only parameters not on a path separator boundary must still match
with a linear search after this change (e.g. `/foo-:bar/`).
This results in performance for constrainted routes that matches that of
ones using the default regexp.
Benchmark:
https://gist.github.com/theojulienne/e91fc338d180e1710e29c81a5d701fab
Before:
```
Calculating -------------------------------------
without params 6.466k (±12.7%) i/s - 31.648k in 5.009453s
params without constraints
5.867k (±12.9%) i/s - 28.842k in 5.032637s
params with constraints
909.661 (± 7.9%) i/s - 4.536k in 5.023534s
```
After:
```
Calculating -------------------------------------
without params 6.387k (±11.9%) i/s - 31.728k in 5.068939s
params without constraints
5.824k (±13.2%) i/s - 28.650k in 5.043701s
params with constraints
5.406k (±11.7%) i/s - 26.931k in 5.076412s
```
For github.com which has many constrainted parameters, a random sampling
of 10 URL patterns can be matched approximately 2-4x faster than before.
This commit fixes symbols as constrains as tested in
6ab985da28
The FSM used to find matching routes was previously limited to patterns
that contained parameters with the default regexp / no constraints. In
large route sets where many parameters are constrained by custom regexp,
these routes all fall back on a slow linear search over the route list.
These custom regexes were not previously able to be included in the FSM
because it transitioned between nodes using only fragments of the URI,
or path separators [/.?], but a custom regex may cross a path separator
boundary. To work around this, the TransitionTable is improved to
support remembering a point within the matching string that we started,
and continuing to attempt to match from that point up to the end of each
token. Only parameters not on a path separator boundary must still match
with a linear search after this change (e.g. `/foo-:bar/`).
This results in performance for constrainted routes that matches that of
ones using the default regexp.
Benchmark:
https://gist.github.com/theojulienne/e91fc338d180e1710e29c81a5d701fab
Before:
```
Calculating -------------------------------------
without params 6.466k (±12.7%) i/s - 31.648k in 5.009453s
params without constraints
5.867k (±12.9%) i/s - 28.842k in 5.032637s
params with constraints
909.661 (± 7.9%) i/s - 4.536k in 5.023534s
```
After:
```
Calculating -------------------------------------
without params 6.387k (±11.9%) i/s - 31.728k in 5.068939s
params without constraints
5.824k (±13.2%) i/s - 28.650k in 5.043701s
params with constraints
5.406k (±11.7%) i/s - 26.931k in 5.076412s
```
For github.com which has many constrainted parameters, a random sampling
of 10 URL patterns can be matched approximately 2-4x faster than before.
* Use public API to add argument to the selenium driver.
While `args` is also public API it doesn't know how to handle if no
argument is being set yet in Selenium 4.
* Fix assertions to match return on Selenium 4
Because `ActionDispatch::SSL` is included higher up in the middleware stack than `ActionDispatch::ShowExceptions`, it should ideally not be raising any exceptions.
In this case, `ActionDispatch::Request#{get,head}?` are called, which check if the HTTP method is valid. If it isn't, `ActionController::UnknownHttpMethod` is raised. Instead of calling the Rack-provided predicate methods, we leverage `raw_request_method`.
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, 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.
In 90e710d7672b928ce6bb3ec05f8f2c05338be6c9 the FeaturePolicy middleware
was renamed to PermissionsPolicy as this will be new name of the header
as used by browsers.
The Permissions-Policy header requires a different implementation and
isn't yet supported by all browsers. To avoid having to rename the
middleware in the future, we keep the new name for the Middleware, but
use the old implementation and header name.
There are several `cookies` methods that appear when searching the API
documentation, but none of them are the method commonly used in
controllers.
This makes Action Controller's `cookies` method appear in the search
results, and makes the accompanying `ActionDispatch::Cookies`
documentation more discoverable.
In the same way that requests may need to be excluded from forced SSL,
requests may also need to be excluded from the Host Authorization
checks. By providing this additional flexibility more applications
will be able to enable Host Authorization while excluding requests
that may not conform. For example, AWS Classic Load Balancers don't
provide a Host header and cannot be configured to send one. This means
that Host Authorization must be disabled to use the health check
provided by the load balancer. This change will allow an application
to exclude the health check requests from the Host Authorization
requirements.
I've modified the `ActionDispatch::HostAuthorization` middleware to
accept arguments in a similar way to `ActionDispatch::SSL`. The hosts
configuration setting still exists separately as does the
hosts_response_app but I've tried to group the Host Authorization
settings like the ssl_options. It may make sense to deprecate the
global hosts_response_app if it's only used as part of the Host
Authorization failure response. I've also updated the existing tests
as the method signature changed and added new tests to verify the
exclusion functionality.
When wrapping parameters, `_extract_parameters` is called twice for
every request. In most cases, both the `include` and `exclude` options
will be empty. In that case, we can use a logical check to save
allocation of an empty array and another allocation of a new array
concatenating the empty array with the hard-coded `EXCLUDE_PARAMETERS`.
The result is 4 array allocations less per request when wrapping is
enabled and `exclude` is not set.
This commit allows Action Text to be used without having an
ApplicationController defined. In doing so, it also fixes Action Text
attachments to render the correct URL host in mailers.
It also avoids allocating an ActionController::Renderer per request.
Fixes#37183.
Fixes#35578.
Fixes#36963.
Closes#38714.
Co-authored-by: Jeremy Daer <jeremydaer@gmail.com>
by setting `config.action_dispatch.request_id_header` to the desired value
* Ensure HTTP_X_REQUEST_ID presence to maintain compatiblility
* Use req.headers[] to fetch header rather than ENV methods
* Update configuration doc to match existing descriptions
* Add changelog entry for action_dispatch.request_id_header
if the action does not use a custom encoding, then we can skip checking if we need to fix the encoding on any of the parameters.
Instead of asking the controller about each of the parameters, we can ask the controller to tell us what params to convert once. If the controller returns nothing, we have no work to do.