From 86e3aaab939a67536f007d1633ec19521dba15e9 Mon Sep 17 00:00:00 2001
From: Fabrizio Regini <freegenie@gmail.com>
Date: Mon, 1 Oct 2012 00:00:44 +0200
Subject: Adding filter capability to ActionController logs

---
 actionpack/CHANGELOG.md                            |  6 ++++
 .../lib/action_controller/metal/instrumentation.rb |  2 +-
 actionpack/lib/action_dispatch.rb                  |  1 +
 .../lib/action_dispatch/http/filter_redirect.rb    | 37 ++++++++++++++++++++++
 actionpack/lib/action_dispatch/http/response.rb    |  1 +
 actionpack/test/controller/log_subscriber_test.rb  | 22 +++++++++++++
 guides/source/action_controller_overview.md        | 27 ++++++++++++++--
 railties/lib/rails/application.rb                  |  2 ++
 railties/lib/rails/application/configuration.rb    |  3 +-
 9 files changed, 96 insertions(+), 5 deletions(-)
 create mode 100644 actionpack/lib/action_dispatch/http/filter_redirect.rb

diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 43fd727500..91028e48c8 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,4 +1,10 @@
 ## Rails 4.0.0 (unreleased) ##
+*   Add filter capability to ActionController logs for redirect locations:
+
+        config.filter_redirect << 'http://please.hide.it/'
+
+    *Fabrizio Regini*
+
 *   Fixed a bug that ignores constraints on a glob route. This was caused because the constraint
     regular expression is overwritten when the `routes.rb` file is processed. Fixes #7924
 
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index ca4ae532ca..d3aa8f90c5 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -60,7 +60,7 @@ module ActionController
       ActiveSupport::Notifications.instrument("redirect_to.action_controller") do |payload|
         result = super
         payload[:status]   = response.status
-        payload[:location] = response.location
+        payload[:location] = response.filtered_location
         result
       end
     end
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 1d716a3248..d002babee3 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -75,6 +75,7 @@ module ActionDispatch
     autoload :Parameters
     autoload :ParameterFilter
     autoload :FilterParameters
+    autoload :FilterRedirect
     autoload :Upload
     autoload :UploadedFile, 'action_dispatch/http/upload'
     autoload :URL
diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb
new file mode 100644
index 0000000000..900ce1c646
--- /dev/null
+++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb
@@ -0,0 +1,37 @@
+module ActionDispatch
+  module Http
+    module FilterRedirect
+
+      FILTERED = '[FILTERED]'.freeze # :nodoc:
+
+      def filtered_location
+        if !location_filter.empty? && location_filter_match?
+          FILTERED
+        else
+          location
+        end
+      end
+
+    private
+
+      def location_filter
+        if request.present?
+          request.env['action_dispatch.redirect_filter'] || []
+        else
+          []
+        end
+      end
+
+      def location_filter_match?
+        location_filter.any? do |filter|
+          if String === filter
+            location.include?(filter)
+          elsif Regexp === filter
+            location.match(filter)
+          end
+        end
+      end
+
+    end
+  end
+end
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 11b7534ea4..0f808ac9cf 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -61,6 +61,7 @@ module ActionDispatch # :nodoc:
     cattr_accessor(:default_headers)
 
     include Rack::Response::Helpers
+    include ActionDispatch::Http::FilterRedirect
     include ActionDispatch::Http::Cache::Response
     include MonitorMixin
 
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index 9efb6ab95f..7b4d49be20 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -26,6 +26,10 @@ module Another
       redirect_to "http://foo.bar/"
     end
 
+    def filterable_redirector
+      redirect_to "http://secret.foo.bar/"
+    end
+
     def data_sender
       send_data "cool data", :filename => "file.txt"
     end
@@ -152,6 +156,24 @@ class ACLogSubscriberTest < ActionController::TestCase
     assert_equal "Redirected to http://foo.bar/", logs[1]
   end
 
+  def test_filter_redirect_url_by_string
+    @request.env['action_dispatch.redirect_filter'] = ['secret']
+    get :filterable_redirector
+    wait
+
+    assert_equal 3, logs.size
+    assert_equal "Redirected to [FILTERED]", logs[1]
+  end
+
+  def test_filter_redirect_url_by_regexp
+    @request.env['action_dispatch.redirect_filter'] = [/secret\.foo.+/]
+    get :filterable_redirector
+    wait
+
+    assert_equal 3, logs.size
+    assert_equal "Redirected to [FILTERED]", logs[1]
+  end
+
   def test_send_data
     get :data_sender
     wait
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 69d99becb9..8bd28d5246 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -751,15 +751,36 @@ Now the user can request to get a PDF version of a client just by adding ".pdf"
 GET /clients/1.pdf
 ```
 
-Parameter Filtering
--------------------
+Log Filtering
+-------------
+
+Rails keeps a log file for each environment in the `log` folder. These are extremely useful when debugging what's actually going on in your application, but in a live application you may not want every bit of information to be stored in the log file.
 
-Rails keeps a log file for each environment in the `log` folder. These are extremely useful when debugging what's actually going on in your application, but in a live application you may not want every bit of information to be stored in the log file. You can filter certain request parameters from your log files by appending them to `config.filter_parameters` in the application configuration. These parameters will be marked [FILTERED] in the log.
+### Parameters Filtering
+
+You can filter certain request parameters from your log files by appending them to `config.filter_parameters` in the application configuration. These parameters will be marked [FILTERED] in the log.
 
 ```ruby
 config.filter_parameters << :password
 ```
 
+### Redirects Filtering
+
+Sometimes it's desirable to filter out from log files some sensible locations your application is redirecting to.
+You can do that by using the `config.filter_redirect` configuration option:
+
+```ruby
+config.filter_redirect << 's3.amazonaws.com'
+```
+
+You can set it to a String, a Regexp, or an array of both.
+
+```ruby
+config.filter_redirect.concat ['s3.amazonaws.com', /private_path/]
+```
+
+Matching URLs will be marked as '[FILTERED]'.
+
 Rescue
 ------
 
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index ae3993fbd8..bf3a26d400 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -123,6 +123,7 @@ module Rails
     # Currently stores:
     #
     #   * "action_dispatch.parameter_filter"             => config.filter_parameters
+    #   * "action_dispatch.redirect_filter"              => config.filter_redirect
     #   * "action_dispatch.secret_token"                 => config.secret_token,
     #   * "action_dispatch.show_exceptions"              => config.action_dispatch.show_exceptions
     #   * "action_dispatch.show_detailed_exceptions"     => config.consider_all_requests_local
@@ -149,6 +150,7 @@ module Rails
 
         super.merge({
           "action_dispatch.parameter_filter" => config.filter_parameters,
+          "action_dispatch.redirect_filter" => config.filter_redirect,
           "action_dispatch.secret_token" => config.secret_token,
           "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
           "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 89afeaeec5..f15fc9296d 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -13,7 +13,7 @@ module Rails
                     :railties_order, :relative_url_root, :secret_key_base, :secret_token,
                     :serve_static_assets, :ssl_options, :static_cache_control, :session_options,
                     :time_zone, :reload_classes_only_on_change,
-                    :queue, :queue_consumer, :beginning_of_week
+                    :queue, :queue_consumer, :beginning_of_week, :filter_redirect
 
       attr_writer :log_level
       attr_reader :encoding
@@ -23,6 +23,7 @@ module Rails
         self.encoding = "utf-8"
         @consider_all_requests_local   = false
         @filter_parameters             = []
+        @filter_redirect               = []
         @helpers_paths                 = []
         @serve_static_assets           = true
         @static_cache_control          = nil
-- 
cgit v1.2.3