Repository: rails/rails
File: actionpack/lib/action_controller/structured_event_subscriber.rb (Ruby)

Code before:
      exception_backtrace = exception_backtrace&.delete_prefix("#{Rails.root}/") if defined?(Rails.root) && Rails.root

      emit_event("action_controller.rescue_from_handled",
        exception_class: exception.class.name,
        exception_message: exception.message,
        exception_backtrace:
      )
    end

    def send_file(event)
      emit_event("action_controller.file_sent", path: event.payload[:path], duration_ms: event.duration.round(1))
    end

    def redirect_to(event)
      emit_event("action_controller.redirected", location: event.payload[:location])
    end

    def send_data(event)
      emit_event("action_controller.data_sent", filename: event.payload[:filename], duration_ms: event.duration.round(1))
    end

    def open_redirect(event)
      payload = event.payload
      stacktrace = payload[:stack_trace]&.first
      stacktrace = stacktrace&.delete_prefix("#{Rails.root}/") if defined?(Rails.root) && Rails.root
      emit_event("action_controller.open_redirect_detected",
        location: payload[:location],
        request_method: payload[:request]&.method,
        request_path: payload[:request]&.path,
        stacktrace:
      )
    end

    def unpermitted_parameters(event)
      unpermitted_keys = event.payload[:keys]
      context = event.payload[:context]

      emit_debug_event("action_controller.unpermitted_parameters",
        unpermitted_keys:,
        context: context.except(:request)
      )
    end
    debug_only :unpermitted_parameters

    def write_fragment(event)
      fragment_cache(__method__, event)
    end

    def read_fragment(event)
      fragment_cache(__method__, event)
    end

Review comment (bug):
```suggestion
      emit_event("action_controller.open_redirect",
```
I'd rather the event keep the same name as the notification. We do this already for `unpermitted_parameters`. Adding "detected" makes it vague as to when it actually happened IMO.

Code after:
      exception_backtrace = exception_backtrace&.delete_prefix("#{Rails.root}/") if defined?(Rails.root) && Rails.root

      emit_event("action_controller.rescue_from_handled",
        exception_class: exception.class.name,
        exception_message: exception.message,
        exception_backtrace:
      )
    end

    def send_file(event)
      emit_event("action_controller.file_sent", path: event.payload[:path], duration_ms: event.duration.round(1))
    end

    def redirect_to(event)
      emit_event("action_controller.redirected", location: event.payload[:location])
    end

    def send_data(event)
      emit_event("action_controller.data_sent", filename: event.payload[:filename], duration_ms: event.duration.round(1))
    end

    def open_redirect(event)
      payload = event.payload

      emit_event("action_controller.open_redirect",
        location: payload[:location],
        request_method: payload[:request]&.method,
        request_path: payload[:request]&.path,
        stacktrace: payload[:stack_trace],
      )
    end

    def unpermitted_parameters(event)
      unpermitted_keys = event.payload[:keys]
      context = event.payload[:context]

      emit_debug_event("action_controller.unpermitted_parameters",
        unpermitted_keys:,
        context: context.except(:request)
      )
    end
    debug_only :unpermitted_parameters

    def write_fragment(event)
      fragment_cache(__method__, event)
    end

    def read_fragment(event)
      fragment_cache(__method__, event)
    end