Class: Otto::Route

Inherits:
Object
  • Object
show all
Defined in:
lib/otto/route.rb

Overview

Otto::Route

A Route is a definition of a URL path and the method to call when that path is requested. Each route represents a single line in a routes file.

Routes include built-in security features:

  • Class name validation to prevent code injection

  • Automatic security header injection

  • CSRF protection when enabled

  • Input validation and sanitization

e.g.

GET   /uri/path      YourApp.method
GET   /uri/path2     YourApp#method

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(verb, path, definition) ⇒ Route

Initialize a new route with security validations

Parameters:

  • verb (String)

    HTTP verb (GET, POST, PUT, DELETE, etc.)

  • path (String)

    URL path pattern with optional parameters

  • definition (String)

    Class and method definition with optional key-value parameters Examples:

    "Class.method" (traditional)
    "Class#method" (traditional)
    "V2::Logic::AuthSession auth=authenticated response=redirect" (enhanced)
    

Raises:

  • (ArgumentError)

    if definition format is invalid or class name is unsafe



49
50
51
52
53
54
55
56
57
# File 'lib/otto/route.rb', line 49

def initialize(verb, path, definition)
  pattern, keys = *compile(path)

  # Create immutable route definition
  @route_definition = Otto::RouteDefinition.new(verb, path, definition, pattern: pattern, keys: keys)

  # Resolve the class
  @klass = Otto::Security::ConstantResolver.safe_const_get(@route_definition.klass_name)
end

Instance Attribute Details

#klassClass (readonly)

Returns The resolved class object.

Returns:

  • (Class)

    The resolved class object



35
36
37
# File 'lib/otto/route.rb', line 35

def klass
  @klass
end

#ottoObject

Returns the value of attribute otto.



37
38
39
# File 'lib/otto/route.rb', line 37

def otto
  @otto
end

#route_definitionOtto::RouteDefinition (readonly)

Returns The immutable route definition.

Returns:



32
33
34
# File 'lib/otto/route.rb', line 32

def route_definition
  @route_definition
end

Instance Method Details

#call(env, extra_params = {}) ⇒ Array

Execute the route by calling the associated class method

This method handles the complete request/response cycle with built-in security:

  • Processes parameters through the security layer

  • Adds configured security headers to the response

  • Extends request/response with security helpers when enabled

  • Provides CSRF and validation helpers to the target class

Parameters:

  • env (Hash)

    Rack environment hash

  • extra_params (Hash) (defaults to: {})

    Additional parameters to merge (default: {})

Returns:

  • (Array)

    Rack response array [status, headers, body]



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/otto/route.rb', line 103

def call(env, extra_params = {})
  extra_params ||= {}
  req            = otto.request_class.new(env)
  res            = otto.response_class.new
  res.request = req

  # Make security config available to response helpers
  env['otto.security_config'] = otto.security_config if otto.respond_to?(:security_config) && otto.security_config

  # NEW: Make route definition and options available to middleware and handlers
  env['otto.route_definition'] = @route_definition
  env['otto.route_options'] = @route_definition.options

  # Process parameters through security layer
  req.params.merge! extra_params
  req.params.replace Otto::Static.indifferent_params(req.params)

  # Add security headers
  if otto.respond_to?(:security_config) && otto.security_config
    otto.security_config.security_headers.each do |header, value|
      res.headers[header] = value
    end
  end

  klass.extend Otto::Route::ClassMethods
  klass.otto = otto

  # Add security helpers if CSRF is enabled
  if otto.respond_to?(:security_config) && otto.security_config&.csrf_enabled?
    res.extend Otto::Security::CSRFHelpers
  end

  # Add validation helpers
  res.extend Otto::Security::ValidationHelpers

  # NEW: Use the pluggable route handler factory (Phase 4)
  # This replaces the hardcoded execution pattern with a factory approach
  if otto&.route_handler_factory
    handler = otto.route_handler_factory.create_handler(@route_definition, otto)
    handler.call(env, extra_params)
  else
    # Fallback to legacy behavior for backward compatibility
    inst = nil
    result = case kind
             when :instance
               inst = klass.new req, res
               inst.send(name)
             when :class
               klass.send(name, req, res)
             else
               raise "Unsupported kind for #{definition}: #{kind}"
             end

    # Handle response based on route options
    response_type = @route_definition.response_type
    if response_type != 'default'
      context = {
        logic_instance: (kind == :instance ? inst : nil),
           status_code: nil,
         redirect_path: nil,
      }

      Otto::ResponseHandlers::HandlerFactory.handle_response(result, res, response_type, context)
    end

    res.body = [res.body] unless res.body.respond_to?(:each)
    res.finish
  end
end

#definitionObject



68
69
70
# File 'lib/otto/route.rb', line 68

def definition
  @route_definition.definition
end

#keysObject



76
77
78
# File 'lib/otto/route.rb', line 76

def keys
  @route_definition.keys
end

#kindObject



84
85
86
# File 'lib/otto/route.rb', line 84

def kind
  @route_definition.kind
end

#nameObject



80
81
82
# File 'lib/otto/route.rb', line 80

def name
  @route_definition.method_name
end

#pathObject



64
65
66
# File 'lib/otto/route.rb', line 64

def path
  @route_definition.path
end

#patternObject



72
73
74
# File 'lib/otto/route.rb', line 72

def pattern
  @route_definition.pattern
end

#route_optionsObject



88
89
90
# File 'lib/otto/route.rb', line 88

def route_options
  @route_definition.options
end

#verbObject

Delegate common methods to route_definition for backward compatibility



60
61
62
# File 'lib/otto/route.rb', line 60

def verb
  @route_definition.verb
end