Module: Contrast::Framework::Rack::Support

Extended by:
BaseSupport, Patch::Support
Defined in:
lib/contrast/framework/rack/support.rb

Overview

Used when Rack is present to define framework specific behavior. For now, the only part of this implemented is the Patch Support.

Constant Summary collapse

RACK_REQUEST_PATH =
'REQUEST_PATH'
RACK_SERVER_NAME =
'SERVER_NAME'

Class Method Summary collapse

Methods included from BaseSupport

after_load_patches, application_name, before_load_patches!, collect_routes, current_route_coverage, detection_class, retrieve_request, server_type, streaming?, version

Methods included from Patch::Support

after_load_patches

Class Method Details

.application_nameString

Returns the Rack application name.

Returns:

  • (String)

    the Rack application name



32
33
34
# File 'lib/contrast/framework/rack/support.rb', line 32

def application_name
  'Rack Application'
end

.application_rootObject



36
37
38
# File 'lib/contrast/framework/rack/support.rb', line 36

def application_root
  Dir.pwd
end

.collect_routesArray<Contrast::Agent::Reporting::DiscoveredRoute>

Find all the predefined routes for this application

Extracting the Rack application routes is not trivial. Routes are evaluated dynamically when a request comes in, so they are not loaded before and stored in a data structure available somewhere. This mean that route discovery is only available through the rack map, but this is limited as not showing the actual method (GET, POST, etc…). For now The Agent will use only the current_route_coverage for Rack applications.

Returns:

Raises:

  • (NoMethodError)

    raises error if subclass does not implement this method



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/contrast/framework/rack/support.rb', line 55

def collect_routes
  # return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless defined?(Rack)
  # Rack::URLMap is used for mapping different rack apps to different paths.
  # The Rack app could be separated into smaller rack applications.
  # Rack::Builder is another option.
  # return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless rack_map

  # This method is disabled for now, as it is not returning the actual routes. Code is left for as
  # comment for future reference.
  #
  # routes = []
  # rack_map.any? do |path, meta|
  #   routes << Contrast::Agent::Reporting::DiscoveredRoute.from_rack_route(meta[1], meta[0], path)
  # end
  # routes
  Contrast::Utils::ObjectShare::EMPTY_ARRAY
end

.current_route_coverage(request, _controller = nil, full_route = nil) ⇒ Contrast::Agent::Reporting::RouteCoverage?

Returns the route coverage object or nil if no route.

Parameters:

  • request (Contrast::Agent::Request)

    a contrast tracked request.

  • _controller (::Sinatra::Base) (defaults to: nil)

    optionally use this controller instead of global ::Sinatra::Base.

Returns:



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/contrast/framework/rack/support.rb', line 78

def current_route_coverage request, _controller = nil, full_route = nil
  method = request.env[::Rack::REQUEST_METHOD] # GET, PUT, POST, etc...

  full_route ||= request.env.fetch(::Rack::PATH_INFO, nil)
  full_route = request.env.fetch(RACK_REQUEST_PATH, nil) if Contrast::Utils::DuckUtils.empty_duck?(full_route)
  return unless method

  # If we are here and have method but the route is "" we might be expecting the home page.
  full_route = '/' if Contrast::Utils::DuckUtils.empty_duck?(full_route) &&
      request.env.fetch(RACK_SERVER_NAME, nil)

  route_coverage = Contrast::Agent::Reporting::RouteCoverage.new
  # We might not have controller, or even if there is defined one, it could not bare the name of the
  # route to match as an object, it could be one router class with base controller with several methods
  # describing each class, search for final controller might be resource heavy, and not efficient.
  # For now to identify the controller the Agent will use the route name, this may lead to recording
  # of false routes, but it is better than nothing. If route do no match a pattern it is a good practice
  # to notify the user by displaying a not found page, in a sense this is a exercise of the application, but
  # not correctly recorded controller name. Try to see if there is a define Rack::URLMap, and use it first.
  mapped_controller = rack_map[full_route]&.last
  final_controller = mapped_controller || full_route
  route_coverage.attach_rack_based_data(final_controller, method, nil, full_route)
  route_coverage
end

.detection_classObject



20
21
22
# File 'lib/contrast/framework/rack/support.rb', line 20

def detection_class
  'Rack'
end

.rack_mapHash<String, Array<String>>

Try and get map of Rack application { “path” => [“pattern”, “controller”] }.

Returns:



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/contrast/framework/rack/support.rb', line 106

def rack_map
  rack_map = {}
  maps = ObjectSpace.each_object(::Rack::URLMap).to_a
  maps.any? do |map|
    mapping = map.instance_variable_get(:@mapping)
    mapping.any? do |arr|
      path = arr[1]
      pattern = arr[2]
      controller = arr[3]&.cs__class&.cs__name
      rack_map[path] = [pattern, controller] if path&.cs__is_a?(String) && controller
    end
  end
  rack_map
rescue StandardError
  {}
end

.retrieve_request(env) ⇒ Object



123
124
125
# File 'lib/contrast/framework/rack/support.rb', line 123

def retrieve_request env
  ::Rack::Request.new(env)
end

.server_typeString

Returns the server type.

Returns:

  • (String)

    the server type



41
42
43
# File 'lib/contrast/framework/rack/support.rb', line 41

def server_type
  'Rack'
end

.versionString

Returns the Rack version.

Returns:

  • (String)

    the Rack version



25
26
27
28
29
# File 'lib/contrast/framework/rack/support.rb', line 25

def version
  ::Rack.version
rescue StandardError
  ''
end