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



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

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 = safe_const_get(@route_definition.klass_name)
end

Instance Attribute Details

#klassClass (readonly)

Returns The resolved class object.

Returns:

  • (Class)

    The resolved class object



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

def klass
  @klass
end

#ottoObject

Returns the value of attribute otto.



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

def otto
  @otto
end

#route_definitionOtto::RouteDefinition (readonly)

Returns The immutable route definition.

Returns:



30
31
32
# File 'lib/otto/route.rb', line 30

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]



101
102
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
# File 'lib/otto/route.rb', line 101

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



66
67
68
# File 'lib/otto/route.rb', line 66

def definition
  @route_definition.definition
end

#keysObject



74
75
76
# File 'lib/otto/route.rb', line 74

def keys
  @route_definition.keys
end

#kindObject



82
83
84
# File 'lib/otto/route.rb', line 82

def kind
  @route_definition.kind
end

#nameObject



78
79
80
# File 'lib/otto/route.rb', line 78

def name
  @route_definition.method_name
end

#pathObject



62
63
64
# File 'lib/otto/route.rb', line 62

def path
  @route_definition.path
end

#patternObject



70
71
72
# File 'lib/otto/route.rb', line 70

def pattern
  @route_definition.pattern
end

#route_optionsObject



86
87
88
# File 'lib/otto/route.rb', line 86

def route_options
  @route_definition.options
end

#verbObject

Delegate common methods to route_definition for backward compatibility



58
59
60
# File 'lib/otto/route.rb', line 58

def verb
  @route_definition.verb
end