Module: Hooks::App::Helpers
- Included in:
- API, CatchallEndpoint
- Defined in:
- lib/hooks/app/helpers.rb
Instance Method Summary collapse
-
#enforce_request_limits(config, request_context = {}) ⇒ void
Enforce request size and timeout limits.
-
#ip_filtering!(headers, endpoint_config, global_config, request_context, env) ⇒ void
Verifies the incoming request passes the configured IP filtering rules.
-
#load_handler(handler_class_name) ⇒ Object
Load handler class.
-
#parse_payload(raw_body, headers, symbolize: false) ⇒ Hash, String
Parse request payload.
-
#uuid ⇒ String
Generate a unique identifier (UUID).
Instance Method Details
#enforce_request_limits(config, request_context = {}) ⇒ void
Timeout enforcement should be handled at the server level (e.g., Puma)
This method returns an undefined value.
Enforce request size and timeout limits
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/hooks/app/helpers.rb', line 25 def enforce_request_limits(config, request_context = {}) # Optimized content length check - check most common sources first content_length = request.content_length if respond_to?(:request) && request.respond_to?(:content_length) content_length ||= headers["Content-Length"] || headers["CONTENT_LENGTH"] || headers["content-length"] || headers["HTTP_CONTENT_LENGTH"] || env["CONTENT_LENGTH"] || env["HTTP_CONTENT_LENGTH"] content_length = content_length&.to_i if content_length && content_length > config[:request_limit] request_id = request_context&.dig(:request_id) error!({ error: "request_body_too_large", message: "request body too large", request_id: }, 413) end # Note: Timeout enforcement would typically be handled at the server level (Puma, etc.) end |
#ip_filtering!(headers, endpoint_config, global_config, request_context, env) ⇒ void
This method will halt execution with an error if IP filtering rules fail.
This method returns an undefined value.
Verifies the incoming request passes the configured IP filtering rules.
This method assumes that the client IP address is available in the request headers (e.g., ‘X-Forwarded-For`). The headers that is used is configurable via the endpoint configuration. It checks the IP address against the allowed and denied lists defined in the endpoint configuration. If the IP address is not allowed, it instantly returns an error response via the `error!` method. If the IP filtering configuration is missing or invalid, it raises an error. If IP filtering is configured at the global level, it will also check against the global configuration first, and then against the endpoint-specific configuration.
110 111 112 |
# File 'lib/hooks/app/helpers.rb', line 110 def ip_filtering!(headers, endpoint_config, global_config, request_context, env) Hooks::Core::Network::IpFiltering.ip_filtering!(headers, endpoint_config, global_config, request_context, env) end |
#load_handler(handler_class_name) ⇒ Object
Load handler class
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/hooks/app/helpers.rb', line 81 def load_handler(handler_class_name) # Get handler class from loaded plugins registry (the registry is populated at boot time) # NOTE: We create a new instance per request (not reuse boot-time instances) because: # - Security: Prevents state pollution and information leakage between requests # - Thread Safety: Avoids race conditions from shared instance state # - Performance: Handler instantiation is fast; reusing instances provides minimal gain # - Memory: Allows garbage collection of short-lived objects (Ruby GC optimization) handler_class = Core::PluginLoader.get_handler_plugin(handler_class_name) return handler_class.new end |
#parse_payload(raw_body, headers, symbolize: false) ⇒ Hash, String
Parse request payload
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/hooks/app/helpers.rb', line 52 def parse_payload(raw_body, headers, symbolize: false) # Optimized content type check - check most common header first content_type = headers["Content-Type"] || headers["CONTENT_TYPE"] || headers["content-type"] || headers["HTTP_CONTENT_TYPE"] # Try to parse as JSON if content type suggests it or if it looks like JSON if content_type&.include?("application/json") || (raw_body.strip.start_with?("{", "[") rescue false) begin # Security: Limit JSON parsing depth and complexity to prevent JSON bombs parsed_payload = safe_json_parse(raw_body) # Note: symbolize parameter is kept for backward compatibility but defaults to false parsed_payload = parsed_payload.transform_keys(&:to_sym) if symbolize && parsed_payload.is_a?(Hash) return parsed_payload rescue JSON::ParserError, ArgumentError => e # If JSON parsing fails or security limits exceeded, return raw body if e..include?("nesting") || e..include?("depth") log.warn("JSON parsing limit exceeded: #{e.}") end end end # Return raw body for all other cases raw_body end |
#uuid ⇒ String
Generate a unique identifier (UUID)
14 15 16 |
# File 'lib/hooks/app/helpers.rb', line 14 def uuid SecureRandom.uuid end |