Module: Datadog::AppSec::APISecurity::RouteExtractor
- Defined in:
- lib/datadog/appsec/api_security/route_extractor.rb
Overview
This is a helper module to extract the route pattern from the Rack::Request.
Constant Summary collapse
- SINATRA_ROUTE_KEY =
'sinatra.route'
- SINATRA_ROUTE_SEPARATOR =
' '
- GRAPE_ROUTE_KEY =
'grape.routing_args'
- RAILS_ROUTE_KEY =
'action_dispatch.route_uri_pattern'
- RAILS_ROUTES_KEY =
'action_dispatch.routes'
- RAILS_PATH_PARAMS_KEY =
'action_dispatch.request.path_parameters'
- RAILS_FORMAT_SUFFIX =
'(.:format)'
Class Method Summary collapse
-
.route_pattern(request) ⇒ Object
HACK: We rely on the fact that each contrib will modify ‘request.env` and store information sufficient to compute the canonical route (ex: `/users/:id`).
Class Method Details
.route_pattern(request) ⇒ Object
HACK: We rely on the fact that each contrib will modify ‘request.env`
and store information sufficient to compute the canonical
route (ex: `/users/:id`).
When contribs like Sinatra or Grape are used, they could be mounted
into the Rails app, hence you can see the use of the `script_name`
that will contain the path prefix of the mounted app.
Rack
does not support named arguments, so we have to use `path`
Sinatra
uses `sinatra.route` with a string like "GET /users/:id"
Grape
uses `grape.routing_args` with a hash with a `:route_info` key
that contains a `Grape::Router::Route` object that contains
`Grape::Router::Pattern` object with an `origin` method
Rails < 7.1 (slow path)
uses `action_dispatch.routes` to store `ActionDispatch::Routing::RouteSet`
which can recognize requests
Rails > 7.1 (fast path)
uses `action_dispatch.route_uri_pattern` with a string like
"/users/:id(.:format)"
WARNING: This method works only after the request has been routed.
WARNING: In Rails > 7.1 when a route was not found,
action_dispatch.route_uri_pattern will not be set.
In Rails < 7.1 it also will not be set even if a route was found,
but in this case action_dispatch.request.path_parameters won't be empty.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/datadog/appsec/api_security/route_extractor.rb', line 45 def self.route_pattern(request) if request.env.key?(GRAPE_ROUTE_KEY) pattern = request.env[GRAPE_ROUTE_KEY][:route_info]&.pattern&.origin "#{request.script_name}#{pattern}" elsif request.env.key?(SINATRA_ROUTE_KEY) pattern = request.env[SINATRA_ROUTE_KEY].split(SINATRA_ROUTE_SEPARATOR, 2)[1] "#{request.script_name}#{pattern}" elsif request.env.key?(RAILS_ROUTE_KEY) request.env[RAILS_ROUTE_KEY].delete_suffix(RAILS_FORMAT_SUFFIX) elsif request.env.key?(RAILS_ROUTES_KEY) && !request.env.fetch(RAILS_PATH_PARAMS_KEY, {}).empty? pattern = request.env[RAILS_ROUTES_KEY].router .recognize(request) { |route, _| break route.path.spec.to_s } # NOTE: If rails is unable to recognize request it returns empty Array pattern = nil if pattern&.empty? # NOTE: If rails can't recognize the request, we are going to fallback # to generic request path (pattern || request.path).delete_suffix(RAILS_FORMAT_SUFFIX) else request.path end end |