Class: Otto
- Inherits:
-
Object
- Object
- Otto
- Extended by:
- ClassMethods
- Includes:
- CaddyTLS::Core, Core::Configuration, Core::ErrorHandler, Core::FileSafety, Core::HelperRegistry, Core::LifecycleHooks, Core::MiddlewareManagement, Core::Router, Core::StaticMounts, Core::UriGenerator, MCP::Core, Privacy::Core, Security::Core
- Defined in:
- lib/otto.rb,
lib/otto/route.rb,
lib/otto/utils.rb,
lib/otto/errors.rb,
lib/otto/locale.rb,
lib/otto/static.rb,
lib/otto/privacy.rb,
lib/otto/request.rb,
lib/otto/env_keys.rb,
lib/otto/mcp/core.rb,
lib/otto/response.rb,
lib/otto/mcp/errors.rb,
lib/otto/mcp/server.rb,
lib/otto/core/router.rb,
lib/otto/mcp/options.rb,
lib/otto/helpers/base.rb,
lib/otto/mcp/endpoint.rb,
lib/otto/mcp/protocol.rb,
lib/otto/mcp/registry.rb,
lib/otto/privacy/core.rb,
lib/otto/design_system.rb,
lib/otto/locale/config.rb,
lib/otto/security/core.rb,
lib/otto/security/csrf.rb,
lib/otto/caddy_tls/core.rb,
lib/otto/core/freezable.rb,
lib/otto/mcp/auth/token.rb,
lib/otto/privacy/config.rb,
lib/otto/route_handlers.rb,
lib/otto/logging_helpers.rb,
lib/otto/security/config.rb,
lib/otto/caddy_tls/server.rb,
lib/otto/core/file_safety.rb,
lib/otto/mcp/route_parser.rb,
lib/otto/route_definition.rb,
lib/otto/locale/middleware.rb,
lib/otto/mcp/rate_limiting.rb,
lib/otto/response_handlers.rb,
lib/otto/core/configuration.rb,
lib/otto/core/error_handler.rb,
lib/otto/core/static_mounts.rb,
lib/otto/core/uri_generator.rb,
lib/otto/helpers/validation.rb,
lib/otto/privacy/ip_privacy.rb,
lib/otto/security/csp/nonce.rb,
lib/otto/security/validator.rb,
lib/otto/optional_dependency.rb,
lib/otto/route_handlers/base.rb,
lib/otto/security/csp/parser.rb,
lib/otto/security/csp/policy.rb,
lib/otto/security/csp/report.rb,
lib/otto/security/csp/writer.rb,
lib/otto/core/helper_registry.rb,
lib/otto/core/lifecycle_hooks.rb,
lib/otto/privacy/asn_resolver.rb,
lib/otto/privacy/geo_resolver.rb,
lib/otto/core/middleware_stack.rb,
lib/otto/mcp/schema_validation.rb,
lib/otto/route_handlers/lambda.rb,
lib/otto/security/configurator.rb,
lib/otto/security/rate_limiter.rb,
lib/otto/response_handlers/auto.rb,
lib/otto/response_handlers/base.rb,
lib/otto/response_handlers/json.rb,
lib/otto/response_handlers/view.rb,
lib/otto/route_handlers/factory.rb,
lib/otto/security/rate_limiting.rb,
lib/otto/security/authentication.rb,
lib/otto/security/csrf_validation.rb,
lib/otto/caddy_tls/localhost_guard.rb,
lib/otto/response_handlers/default.rb,
lib/otto/response_handlers/factory.rb,
lib/otto/core/middleware_management.rb,
lib/otto/privacy/user_agent_privacy.rb,
lib/otto/response_handlers/redirect.rb,
lib/otto/route_handlers/logic_class.rb,
lib/otto/security/constant_resolver.rb,
lib/otto/privacy/anonymizer_resolver.rb,
lib/otto/route_handlers/class_method.rb,
lib/otto/security/csp/request_extras.rb,
lib/otto/privacy/redacted_fingerprint.rb,
lib/otto/security/authorization_error.rb,
lib/otto/security/csp/emit_middleware.rb,
lib/otto/route_handlers/instance_method.rb,
lib/otto/security/csp/report_middleware.rb,
lib/otto/security/csrf_enforcement_wrapper.rb,
lib/otto/security/middleware/csrf_middleware.rb,
lib/otto/security/authentication/auth_failure.rb,
lib/otto/security/authentication/auth_strategy.rb,
lib/otto/security/authentication/strategy_result.rb,
lib/otto/security/middleware/ip_privacy_middleware.rb,
lib/otto/security/middleware/rate_limit_middleware.rb,
lib/otto/security/middleware/validation_middleware.rb,
lib/otto/security/authentication/route_auth_wrapper.rb,
lib/otto/security/authentication/authorization_failure.rb,
lib/otto/security/authentication/strategies/role_strategy.rb,
lib/otto/security/authentication/strategies/noauth_strategy.rb,
lib/otto/security/authentication/strategies/api_key_strategy.rb,
lib/otto/security/authentication/strategies/session_strategy.rb,
lib/otto/security/authentication/strategies/permission_strategy.rb,
lib/otto/security/authentication/route_auth_wrapper/response_builder.rb,
lib/otto/security/authentication/route_auth_wrapper/strategy_resolver.rb,
lib/otto/security/authentication/route_auth_wrapper/role_authorization.rb
Overview
lib/otto/security/authentication/authorization_failure.rb
frozen_string_literal: true
Defined Under Namespace
Modules: BaseHelpers, CaddyTLS, ClassMethods, Core, DesignSystem, EnvKeys, Locale, LoggingHelpers, MCP, OptionalDependency, Privacy, ResponseHandlers, RouteHandlers, Security, Static, Utils Classes: BadRequestError, ForbiddenError, HTTPError, NotFoundError, OptionalDependencyError, PayloadTooLargeError, Request, Response, Route, RouteDefinition, RouteDefinitionError, UnauthorizedError
Constant Summary collapse
- LIB_HOME =
__dir__- POSITIONAL_PARAMETER_TYPES =
Parameter types (from Proc#parameters / Method#parameters) that consume one positional argument each. See #fallback_call_args.
%i[req opt].freeze
- StrategyResult =
Top-level backward compatibility aliases
Security::Authentication::StrategyResult
- AuthFailure =
Security::Authentication::AuthFailure
- AuthorizationFailure =
Security::Authentication::AuthorizationFailure
Class Attribute Summary collapse
-
.debug ⇒ Object
rubocop:disable ThreadSafety/ClassAndModuleAttributes.
-
.logger ⇒ Object
Otto's logger.
Instance Attribute Summary collapse
-
#auth_config ⇒ Object
readonly
Returns the value of attribute auth_config.
-
#caddy_tls_server ⇒ Object
readonly
Returns the value of attribute caddy_tls_server.
-
#error_handlers ⇒ Object
readonly
Returns the value of attribute error_handlers.
-
#locale_config ⇒ Object
readonly
Returns the value of attribute locale_config.
-
#mcp_server ⇒ Object
readonly
Returns the value of attribute mcp_server.
-
#middleware ⇒ Object
readonly
Returns the value of attribute middleware.
-
#not_found ⇒ Object
Returns the value of attribute not_found.
-
#option ⇒ Object
(also: #options, #config)
readonly
Returns the value of attribute option.
-
#request_class ⇒ Object
readonly
Returns the value of attribute request_class.
-
#response_class ⇒ Object
readonly
Returns the value of attribute response_class.
-
#route_definitions ⇒ Object
readonly
Returns the value of attribute route_definitions.
-
#route_handler_factory ⇒ Object
readonly
Returns the value of attribute route_handler_factory.
-
#routes ⇒ Object
readonly
Returns the value of attribute routes.
-
#routes_by_definition ⇒ Object
readonly
Returns the value of attribute routes_by_definition.
-
#routes_literal ⇒ Object
readonly
Returns the value of attribute routes_literal.
-
#security ⇒ Object
readonly
Returns the value of attribute security.
-
#security_config ⇒ Object
readonly
Returns the value of attribute security_config.
-
#server_error ⇒ Object
Returns the value of attribute server_error.
-
#static_route ⇒ Object
readonly
Returns the value of attribute static_route.
Class Method Summary collapse
-
.structured_log(level, message, data = {}) ⇒ Object
Helper method for structured logging that works with both standard Logger and structured loggers.
Instance Method Summary collapse
-
#call(env) ⇒ Object
Main Rack application interface.
-
#initialize(path = nil, opts = {}) ⇒ Otto
constructor
A new instance of Otto.
Methods included from ClassMethods
default, env?, load, path, unfreeze_for_testing
Constructor Details
#initialize(path = nil, opts = {}) ⇒ Otto
Returns a new instance of Otto.
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 |
# File 'lib/otto.rb', line 137 def initialize(path = nil, opts = {}) constructed = false initialize_core_state (path, opts) initialize_configurations(opts) Otto.logger.debug "new Otto: #{opts}" if Otto.debug load(path) unless path.nil? super() # Auto-register all Otto framework error classes # This allows Logic classes and framework code to raise appropriate errors # without requiring manual registration in implementing projects register_framework_errors # Build the middleware app once after all initialization is complete build_app! # Configuration freezing is deferred until first request to support # multi-step initialization (e.g., multi-app architectures). # This allows adding auth strategies, middleware, etc. after Otto.new # but before processing requests. @freeze_mutex = Mutex.new @configuration_frozen = false constructed = true ensure # A config that committed to a forwarding family during configure_security # is held process-wide; withdraw it if construction failed afterwards # (e.g. a bad routes path), or the dead app would keep vetoing other # families for the life of the process. Otto::Security::Config.release_rack_forwarding_family!(@security_config) if @security_config && !constructed end |
Class Attribute Details
.debug ⇒ Object
rubocop:disable ThreadSafety/ClassAndModuleAttributes
325 326 327 |
# File 'lib/otto.rb', line 325 def debug @debug end |
.logger ⇒ Object
Otto's logger. Never nil: falls back to a default $stdout logger so call
sites can log unconditionally without defensive &. guards. Assign your
own logger (or a null logger to silence) via Otto.logger = ....
331 332 333 |
# File 'lib/otto.rb', line 331 def logger @logger ||= Logger.new($stdout, Logger::INFO) end |
Instance Attribute Details
#auth_config ⇒ Object (readonly)
Returns the value of attribute auth_config.
84 85 86 |
# File 'lib/otto.rb', line 84 def auth_config @auth_config end |
#caddy_tls_server ⇒ Object (readonly)
Returns the value of attribute caddy_tls_server.
84 85 86 |
# File 'lib/otto.rb', line 84 def caddy_tls_server @caddy_tls_server end |
#error_handlers ⇒ Object (readonly)
Returns the value of attribute error_handlers.
84 85 86 |
# File 'lib/otto.rb', line 84 def error_handlers @error_handlers end |
#locale_config ⇒ Object (readonly)
Returns the value of attribute locale_config.
84 85 86 |
# File 'lib/otto.rb', line 84 def locale_config @locale_config end |
#mcp_server ⇒ Object (readonly)
Returns the value of attribute mcp_server.
84 85 86 |
# File 'lib/otto.rb', line 84 def mcp_server @mcp_server end |
#middleware ⇒ Object (readonly)
Returns the value of attribute middleware.
84 85 86 |
# File 'lib/otto.rb', line 84 def middleware @middleware end |
#not_found ⇒ Object
Returns the value of attribute not_found.
84 85 86 |
# File 'lib/otto.rb', line 84 def not_found @not_found end |
#option ⇒ Object (readonly) Also known as: options, config
Returns the value of attribute option.
84 85 86 |
# File 'lib/otto.rb', line 84 def option @option end |
#request_class ⇒ Object (readonly)
Returns the value of attribute request_class.
84 85 86 |
# File 'lib/otto.rb', line 84 def request_class @request_class end |
#response_class ⇒ Object (readonly)
Returns the value of attribute response_class.
84 85 86 |
# File 'lib/otto.rb', line 84 def response_class @response_class end |
#route_definitions ⇒ Object (readonly)
Returns the value of attribute route_definitions.
84 85 86 |
# File 'lib/otto.rb', line 84 def route_definitions @route_definitions end |
#route_handler_factory ⇒ Object (readonly)
Returns the value of attribute route_handler_factory.
84 85 86 |
# File 'lib/otto.rb', line 84 def route_handler_factory @route_handler_factory end |
#routes ⇒ Object (readonly)
Returns the value of attribute routes.
84 85 86 |
# File 'lib/otto.rb', line 84 def routes @routes end |
#routes_by_definition ⇒ Object (readonly)
Returns the value of attribute routes_by_definition.
84 85 86 |
# File 'lib/otto.rb', line 84 def routes_by_definition @routes_by_definition end |
#routes_literal ⇒ Object (readonly)
Returns the value of attribute routes_literal.
84 85 86 |
# File 'lib/otto.rb', line 84 def routes_literal @routes_literal end |
#security ⇒ Object (readonly)
Returns the value of attribute security.
84 85 86 |
# File 'lib/otto.rb', line 84 def security @security end |
#security_config ⇒ Object (readonly)
Returns the value of attribute security_config.
84 85 86 |
# File 'lib/otto.rb', line 84 def security_config @security_config end |
#server_error ⇒ Object
Returns the value of attribute server_error.
84 85 86 |
# File 'lib/otto.rb', line 84 def server_error @server_error end |
#static_route ⇒ Object (readonly)
Returns the value of attribute static_route.
84 85 86 |
# File 'lib/otto.rb', line 84 def static_route @static_route end |
Class Method Details
.structured_log(level, message, data = {}) ⇒ Object
Helper method for structured logging that works with both standard Logger and structured loggers
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/otto.rb', line 336 def structured_log(level, , data = {}) return unless logger # Skip debug logging when Otto.debug is false return if level == :debug && !debug # Sanitize backtrace if present if data.is_a?(Hash) && data[:backtrace].is_a?(Array) data = data.dup data[:backtrace] = Otto::LoggingHelpers.sanitize_backtrace(data[:backtrace]) end # Try structured logging first (SemanticLogger, etc.) if logger.respond_to?(level) && logger.method(level).arity > 1 logger.send(level, , data) else # Fallback to standard logger with formatted string formatted_data = data.empty? ? '' : " -- #{data.inspect}" logger.send(level, "[Otto] #{}#{formatted_data}") end end |
Instance Method Details
#call(env) ⇒ Object
Main Rack application interface
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/otto.rb', line 176 def call(env) # Freeze configuration on first request (thread-safe). # Skipped under RSpec so specs can mutate configuration after construction. # Because of this skip, behavior that depends on a genuinely frozen config # (e.g. CSP violation dispatch through a frozen Config) is NOT exercised by # the normal request path in tests — cover it with specs that freeze # explicitly (see spec/otto/security/csp_reporting_frozen_spec.rb and # spec/otto/configuration_freezing_spec.rb). unless defined?(RSpec) || @configuration_frozen Otto.logger.debug '[Otto] Lazy freezing check: configuration not yet frozen' if Otto.debug @freeze_mutex.synchronize do unless @configuration_frozen Otto.logger.info '[Otto] Freezing configuration on first request (lazy freeze)' freeze_configuration! @configuration_frozen = true Otto.logger.debug '[Otto] Configuration frozen successfully' if Otto.debug end end end # Track request timing for lifecycle hooks start_time = Otto::Utils.now_in_μs request = @request_class.new(env) response_raw = nil begin # Use pre-built middleware app (built once at initialization) response_raw = @app.call(env) rescue StandardError => e response_raw = handle_error(e, env) ensure # Execute request completion hooks if any are registered unless @request_complete_callbacks.empty? begin duration = Otto::Utils.now_in_μs - start_time # Wrap response tuple in Otto::Response for developer-friendly API # Otto's hook API should provide nice abstractions like Otto::Request/Response response = @response_class.new(response_raw[2], response_raw[0], response_raw[1]) @request_complete_callbacks.each do |callback| callback.call(request, response, duration) end rescue StandardError => e Otto.logger.error "[Otto] Request completion hook error: #{e.}" Otto.logger.debug "[Otto] Hook error backtrace: #{e.backtrace.join("\n")}" if Otto.debug end end end response_raw end |