# frozen_string_literal: true class EventNormalizer class NormalizationError < StandardError; end # Normalize an event by populating all the normalized fields def self.normalize_event!(event) normalizer = new(event) normalizer.normalize! event end def initialize(event) @event = event end def normalize! return unless @event.present? normalize_host normalize_action normalize_method normalize_protocol normalize_path_segments end private def normalize_host hostname = extract_hostname return unless hostname host = RequestHost.find_or_create_host(hostname) host.increment_usage! unless host.new_record? @event.request_host = host end def normalize_action raw_action = @event.instance_variable_get(:@raw_action) return unless raw_action.present? action_enum = case raw_action.to_s.downcase when 'allow', 'pass' then :allow when 'deny', 'block' then :deny when 'challenge' then :challenge when 'redirect' then :redirect else :allow end @event.action = action_enum end def normalize_method raw_method = @event.instance_variable_get(:@raw_request_method) return unless raw_method.present? method_enum = case raw_method.to_s.upcase when 'GET' then :get when 'POST' then :post when 'PUT' then :put when 'PATCH' then :patch when 'DELETE' then :delete when 'HEAD' then :head when 'OPTIONS' then :options else :get end @event.request_method = method_enum end def normalize_protocol raw_protocol = @event.instance_variable_get(:@raw_request_protocol) return unless raw_protocol.present? # Store the protocol directly (HTTP/1.1, HTTP/2, etc.) # Could normalize to enum if needed, but keeping as string for flexibility @event.request_protocol = raw_protocol end def normalize_path_segments segments = @event.path_segments_array return if segments.empty? segment_ids = segments.map do |segment| path_segment = PathSegment.find_or_create_segment(segment) path_segment.increment_usage! unless path_segment.new_record? path_segment.id end @event.request_segment_ids = segment_ids end def extract_hostname # Try to extract hostname from various sources return @event.request_hostname if @event.respond_to?(:request_hostname) # Extract from request URL if available if @event.request_url.present? begin uri = URI.parse(@event.request_url) return uri.hostname rescue URI::InvalidURIError nil end end # Extract from payload as fallback if @event.payload.present? url = @event.payload.dig("request", "url") if url.present? begin uri = URI.parse(url) return uri.hostname rescue URI::InvalidURIError nil end end end nil end end