actionpack 6.0.0.beta1 → 6.0.1.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +125 -13
 - data/README.rdoc +2 -1
 - data/lib/abstract_controller/caching/fragments.rb +0 -1
 - data/lib/abstract_controller/translation.rb +1 -0
 - data/lib/action_controller.rb +4 -1
 - data/lib/action_controller/metal.rb +3 -3
 - data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
 - data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
 - data/lib/action_controller/metal/exceptions.rb +2 -2
 - data/lib/action_controller/metal/force_ssl.rb +1 -2
 - data/lib/action_controller/metal/helpers.rb +2 -2
 - data/lib/action_controller/metal/implicit_render.rb +2 -2
 - data/lib/action_controller/metal/live.rb +2 -2
 - data/lib/action_controller/metal/mime_responds.rb +1 -1
 - data/lib/action_controller/metal/params_wrapper.rb +2 -2
 - data/lib/action_controller/metal/redirecting.rb +6 -27
 - data/lib/action_controller/metal/renderers.rb +4 -4
 - data/lib/action_controller/metal/rendering.rb +1 -1
 - data/lib/action_controller/metal/request_forgery_protection.rb +2 -2
 - data/lib/action_controller/metal/strong_parameters.rb +6 -12
 - data/lib/action_controller/renderer.rb +2 -2
 - data/lib/action_controller/template_assertions.rb +1 -1
 - data/lib/action_controller/test_case.rb +3 -2
 - data/lib/action_dispatch.rb +1 -1
 - data/lib/action_dispatch/http/content_security_policy.rb +20 -9
 - data/lib/action_dispatch/http/mime_negotiation.rb +5 -0
 - data/lib/action_dispatch/http/mime_type.rb +13 -1
 - data/lib/action_dispatch/http/response.rb +27 -7
 - data/lib/action_dispatch/http/upload.rb +4 -1
 - data/lib/action_dispatch/journey/formatter.rb +1 -1
 - data/lib/action_dispatch/journey/path/pattern.rb +6 -1
 - data/lib/action_dispatch/journey/route.rb +5 -4
 - data/lib/action_dispatch/journey/routes.rb +0 -1
 - data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
 - data/lib/action_dispatch/middleware/cookies.rb +9 -10
 - data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -2
 - data/lib/action_dispatch/middleware/debug_view.rb +19 -1
 - data/lib/action_dispatch/middleware/exception_wrapper.rb +15 -10
 - data/lib/action_dispatch/middleware/host_authorization.rb +2 -2
 - data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
 - data/lib/action_dispatch/middleware/remote_ip.rb +3 -3
 - data/lib/action_dispatch/middleware/session/cookie_store.rb +4 -3
 - data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
 - data/lib/action_dispatch/middleware/stack.rb +34 -2
 - data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
 - data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
 - data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
 - data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
 - data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +2 -2
 - data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +2 -2
 - data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +6 -2
 - data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
 - data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -1
 - data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
 - data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
 - data/lib/action_dispatch/railtie.rb +6 -2
 - data/lib/action_dispatch/routing.rb +18 -18
 - data/lib/action_dispatch/routing/mapper.rb +26 -11
 - data/lib/action_dispatch/routing/route_set.rb +13 -15
 - data/lib/action_dispatch/system_test_case.rb +43 -5
 - data/lib/action_dispatch/system_testing/browser.rb +38 -7
 - data/lib/action_dispatch/system_testing/driver.rb +10 -1
 - data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -2
 - data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -6
 - data/lib/action_dispatch/testing/assertions.rb +1 -1
 - data/lib/action_dispatch/testing/assertions/routing.rb +8 -1
 - data/lib/action_dispatch/testing/integration.rb +2 -2
 - data/lib/action_dispatch/testing/request_encoder.rb +2 -2
 - data/lib/action_dispatch/testing/test_response.rb +1 -1
 - data/lib/action_pack/gem_version.rb +2 -2
 - metadata +20 -15
 - data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "erb"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "action_dispatch/http/request"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "active_support/actionable_error"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module ActionDispatch
         
     | 
| 
      
 8 
     | 
    
         
            +
              class ActionableExceptions # :nodoc:
         
     | 
| 
      
 9 
     | 
    
         
            +
                cattr_accessor :endpoint, default: "/rails/actions"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(app)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @app = app
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def call(env)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  request = ActionDispatch::Request.new(env)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  return @app.call(env) unless actionable_request?(request)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  ActiveSupport::ActionableError.dispatch(request.params[:error].to_s.safe_constantize, request.params[:action])
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  redirect_to request.params[:location]
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                private
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def actionable_request?(request)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    request.show_exceptions? && request.post? && request.path == endpoint
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def redirect_to(location)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    [302, {
         
     | 
| 
      
 33 
     | 
    
         
            +
                      "Content-Type" => "text/html; charset=#{Response.default_charset}",
         
     | 
| 
      
 34 
     | 
    
         
            +
                      "Content-Length" => body.bytesize.to_s,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      "Location" => location,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    }, [body]]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -338,7 +338,7 @@ module ActionDispatch 
     | 
|
| 
       338 
338 
     | 
    
         | 
| 
       339 
339 
     | 
    
         
             
                  def update_cookies_from_jar
         
     | 
| 
       340 
340 
     | 
    
         
             
                    request_jar = @request.cookie_jar.instance_variable_get(:@cookies)
         
     | 
| 
       341 
     | 
    
         
            -
                    set_cookies = request_jar.reject { |k, _| @delete_cookies.key?(k) }
         
     | 
| 
      
 341 
     | 
    
         
            +
                    set_cookies = request_jar.reject { |k, _| @delete_cookies.key?(k) || @set_cookies.key?(k) }
         
     | 
| 
       342 
342 
     | 
    
         | 
| 
       343 
343 
     | 
    
         
             
                    @cookies.update set_cookies if set_cookies
         
     | 
| 
       344 
344 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -488,13 +488,8 @@ module ActionDispatch 
     | 
|
| 
       488 
488 
     | 
    
         
             
                    end
         
     | 
| 
       489 
489 
     | 
    
         | 
| 
       490 
490 
     | 
    
         
             
                    def cookie_metadata(name, options)
         
     | 
| 
       491 
     | 
    
         
            -
                       
     | 
| 
       492 
     | 
    
         
            -
                        metadata =  
     | 
| 
       493 
     | 
    
         
            -
                        metadata[:purpose] = "cookie.#{name}"
         
     | 
| 
       494 
     | 
    
         
            -
             
     | 
| 
       495 
     | 
    
         
            -
                        metadata
         
     | 
| 
       496 
     | 
    
         
            -
                      else
         
     | 
| 
       497 
     | 
    
         
            -
                        {}
         
     | 
| 
      
 491 
     | 
    
         
            +
                      expiry_options(options).tap do |metadata|
         
     | 
| 
      
 492 
     | 
    
         
            +
                        metadata[:purpose] = "cookie.#{name}" if request.use_cookies_with_metadata
         
     | 
| 
       498 
493 
     | 
    
         
             
                      end
         
     | 
| 
       499 
494 
     | 
    
         
             
                    end
         
     | 
| 
       500 
495 
     | 
    
         | 
| 
         @@ -539,9 +534,13 @@ module ActionDispatch 
     | 
|
| 
       539 
534 
     | 
    
         
             
                      if value
         
     | 
| 
       540 
535 
     | 
    
         
             
                        case
         
     | 
| 
       541 
536 
     | 
    
         
             
                        when needs_migration?(value)
         
     | 
| 
       542 
     | 
    
         
            -
                           
     | 
| 
      
 537 
     | 
    
         
            +
                          Marshal.load(value).tap do |v|
         
     | 
| 
      
 538 
     | 
    
         
            +
                            self[name] = { value: v }
         
     | 
| 
      
 539 
     | 
    
         
            +
                          end
         
     | 
| 
       543 
540 
     | 
    
         
             
                        when rotate
         
     | 
| 
       544 
     | 
    
         
            -
                           
     | 
| 
      
 541 
     | 
    
         
            +
                          serializer.load(value).tap do |v|
         
     | 
| 
      
 542 
     | 
    
         
            +
                            self[name] = { value: v }
         
     | 
| 
      
 543 
     | 
    
         
            +
                          end
         
     | 
| 
       545 
544 
     | 
    
         
             
                        else
         
     | 
| 
       546 
545 
     | 
    
         
             
                          serializer.load(value)
         
     | 
| 
       547 
546 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -4,6 +4,8 @@ require "action_dispatch/http/request" 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require "action_dispatch/middleware/exception_wrapper"
         
     | 
| 
       5 
5 
     | 
    
         
             
            require "action_dispatch/routing/inspector"
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
            require "active_support/actionable_error"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       7 
9 
     | 
    
         
             
            require "action_view"
         
     | 
| 
       8 
10 
     | 
    
         
             
            require "action_view/base"
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
         @@ -60,7 +62,11 @@ module ActionDispatch 
     | 
|
| 
       60 
62 
     | 
    
         
             
                    log_error(request, wrapper)
         
     | 
| 
       61 
63 
     | 
    
         | 
| 
       62 
64 
     | 
    
         
             
                    if request.get_header("action_dispatch.show_detailed_exceptions")
         
     | 
| 
       63 
     | 
    
         
            -
                       
     | 
| 
      
 65 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 66 
     | 
    
         
            +
                        content_type = request.formats.first
         
     | 
| 
      
 67 
     | 
    
         
            +
                      rescue Mime::Type::InvalidMimeType
         
     | 
| 
      
 68 
     | 
    
         
            +
                        render_for_api_request(Mime[:text], wrapper)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
       64 
70 
     | 
    
         | 
| 
       65 
71 
     | 
    
         
             
                      if api_request?(content_type)
         
     | 
| 
       66 
72 
     | 
    
         
             
                        render_for_api_request(content_type, wrapper)
         
     | 
| 
         @@ -142,7 +148,7 @@ module ActionDispatch 
     | 
|
| 
       142 
148 
     | 
    
         
             
                      message = []
         
     | 
| 
       143 
149 
     | 
    
         
             
                      message << "  "
         
     | 
| 
       144 
150 
     | 
    
         
             
                      message << "#{exception.class} (#{exception.message}):"
         
     | 
| 
       145 
     | 
    
         
            -
                      message.concat(exception. 
     | 
| 
      
 151 
     | 
    
         
            +
                      message.concat(exception.annotated_source_code) if exception.respond_to?(:annotated_source_code)
         
     | 
| 
       146 
152 
     | 
    
         
             
                      message << "  "
         
     | 
| 
       147 
153 
     | 
    
         
             
                      message.concat(trace)
         
     | 
| 
       148 
154 
     | 
    
         | 
| 
         @@ -10,7 +10,13 @@ module ActionDispatch 
     | 
|
| 
       10 
10 
     | 
    
         
             
                RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                def initialize(assigns)
         
     | 
| 
       13 
     | 
    
         
            -
                   
     | 
| 
      
 13 
     | 
    
         
            +
                  paths = [RESCUES_TEMPLATE_PATH]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  lookup_context = ActionView::LookupContext.new(paths)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  super(lookup_context, assigns)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def compiled_method_container
         
     | 
| 
      
 19 
     | 
    
         
            +
                  self.class
         
     | 
| 
       14 
20 
     | 
    
         
             
                end
         
     | 
| 
       15 
21 
     | 
    
         | 
| 
       16 
22 
     | 
    
         
             
                def debug_params(params)
         
     | 
| 
         @@ -46,5 +52,17 @@ module ActionDispatch 
     | 
|
| 
       46 
52 
     | 
    
         
             
                    super
         
     | 
| 
       47 
53 
     | 
    
         
             
                  end
         
     | 
| 
       48 
54 
     | 
    
         
             
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def protect_against_forgery?
         
     | 
| 
      
 57 
     | 
    
         
            +
                  false
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def params_valid?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @request.parameters
         
     | 
| 
      
 63 
     | 
    
         
            +
                  rescue ActionController::BadRequest
         
     | 
| 
      
 64 
     | 
    
         
            +
                    false
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
       49 
67 
     | 
    
         
             
              end
         
     | 
| 
       50 
68 
     | 
    
         
             
            end
         
     | 
| 
         @@ -12,6 +12,7 @@ module ActionDispatch 
     | 
|
| 
       12 
12 
     | 
    
         
             
                  "ActionController::UnknownHttpMethod"          => :method_not_allowed,
         
     | 
| 
       13 
13 
     | 
    
         
             
                  "ActionController::NotImplemented"             => :not_implemented,
         
     | 
| 
       14 
14 
     | 
    
         
             
                  "ActionController::UnknownFormat"              => :not_acceptable,
         
     | 
| 
      
 15 
     | 
    
         
            +
                  "Mime::Type::InvalidMimeType"                  => :not_acceptable,
         
     | 
| 
       15 
16 
     | 
    
         
             
                  "ActionController::MissingExactTemplate"       => :not_acceptable,
         
     | 
| 
       16 
17 
     | 
    
         
             
                  "ActionController::InvalidAuthenticityToken"   => :unprocessable_entity,
         
     | 
| 
       17 
18 
     | 
    
         
             
                  "ActionController::InvalidCrossOriginRequest"  => :unprocessable_entity,
         
     | 
| 
         @@ -31,22 +32,34 @@ module ActionDispatch 
     | 
|
| 
       31 
32 
     | 
    
         
             
                  "ActionController::MissingExactTemplate" => "missing_exact_template",
         
     | 
| 
       32 
33 
     | 
    
         
             
                )
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
                cattr_accessor :wrapper_exceptions, default: [
         
     | 
| 
      
 36 
     | 
    
         
            +
                  "ActionView::Template::Error"
         
     | 
| 
      
 37 
     | 
    
         
            +
                ]
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       34 
39 
     | 
    
         
             
                attr_reader :backtrace_cleaner, :exception, :wrapped_causes, :line_number, :file
         
     | 
| 
       35 
40 
     | 
    
         | 
| 
       36 
41 
     | 
    
         
             
                def initialize(backtrace_cleaner, exception)
         
     | 
| 
       37 
42 
     | 
    
         
             
                  @backtrace_cleaner = backtrace_cleaner
         
     | 
| 
       38 
     | 
    
         
            -
                  @exception =  
     | 
| 
      
 43 
     | 
    
         
            +
                  @exception = exception
         
     | 
| 
       39 
44 
     | 
    
         
             
                  @wrapped_causes = wrapped_causes_for(exception, backtrace_cleaner)
         
     | 
| 
       40 
45 
     | 
    
         | 
| 
       41 
46 
     | 
    
         
             
                  expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError)
         
     | 
| 
       42 
47 
     | 
    
         
             
                end
         
     | 
| 
       43 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
                def unwrapped_exception
         
     | 
| 
      
 50 
     | 
    
         
            +
                  if wrapper_exceptions.include?(exception.class.to_s)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    exception.cause
         
     | 
| 
      
 52 
     | 
    
         
            +
                  else
         
     | 
| 
      
 53 
     | 
    
         
            +
                    exception
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
       44 
57 
     | 
    
         
             
                def rescue_template
         
     | 
| 
       45 
58 
     | 
    
         
             
                  @@rescue_templates[@exception.class.name]
         
     | 
| 
       46 
59 
     | 
    
         
             
                end
         
     | 
| 
       47 
60 
     | 
    
         | 
| 
       48 
61 
     | 
    
         
             
                def status_code
         
     | 
| 
       49 
     | 
    
         
            -
                  self.class.status_code_for_exception( 
     | 
| 
      
 62 
     | 
    
         
            +
                  self.class.status_code_for_exception(unwrapped_exception.class.name)
         
     | 
| 
       50 
63 
     | 
    
         
             
                end
         
     | 
| 
       51 
64 
     | 
    
         | 
| 
       52 
65 
     | 
    
         
             
                def application_trace
         
     | 
| 
         @@ -122,14 +135,6 @@ module ActionDispatch 
     | 
|
| 
       122 
135 
     | 
    
         
             
                    Array(@exception.backtrace)
         
     | 
| 
       123 
136 
     | 
    
         
             
                  end
         
     | 
| 
       124 
137 
     | 
    
         | 
| 
       125 
     | 
    
         
            -
                  def original_exception(exception)
         
     | 
| 
       126 
     | 
    
         
            -
                    if @@rescue_responses.has_key?(exception.cause.class.name)
         
     | 
| 
       127 
     | 
    
         
            -
                      exception.cause
         
     | 
| 
       128 
     | 
    
         
            -
                    else
         
     | 
| 
       129 
     | 
    
         
            -
                      exception
         
     | 
| 
       130 
     | 
    
         
            -
                    end
         
     | 
| 
       131 
     | 
    
         
            -
                  end
         
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
138 
     | 
    
         
             
                  def causes_for(exception)
         
     | 
| 
       134 
139 
     | 
    
         
             
                    return enum_for(__method__, exception) unless block_given?
         
     | 
| 
       135 
140 
     | 
    
         | 
| 
         @@ -3,8 +3,8 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require "action_dispatch/http/request"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ActionDispatch
         
     | 
| 
       6 
     | 
    
         
            -
              # This middleware guards from DNS rebinding attacks by  
     | 
| 
       7 
     | 
    
         
            -
              # hosts a request can be sent to.
         
     | 
| 
      
 6 
     | 
    
         
            +
              # This middleware guards from DNS rebinding attacks by explicitly permitting
         
     | 
| 
      
 7 
     | 
    
         
            +
              # the hosts a request can be sent to.
         
     | 
| 
       8 
8 
     | 
    
         
             
              #
         
     | 
| 
       9 
9 
     | 
    
         
             
              # When a request comes to an unauthorized host, the +response_app+
         
     | 
| 
       10 
10 
     | 
    
         
             
              # application will be executed and rendered. If no +response_app+ is given, a
         
     | 
| 
         @@ -21,8 +21,12 @@ module ActionDispatch 
     | 
|
| 
       21 
21 
     | 
    
         
             
                def call(env)
         
     | 
| 
       22 
22 
     | 
    
         
             
                  request      = ActionDispatch::Request.new(env)
         
     | 
| 
       23 
23 
     | 
    
         
             
                  status       = request.path_info[1..-1].to_i
         
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 25 
     | 
    
         
            +
                    content_type = request.formats.first
         
     | 
| 
      
 26 
     | 
    
         
            +
                  rescue Mime::Type::InvalidMimeType
         
     | 
| 
      
 27 
     | 
    
         
            +
                    content_type = Mime[:text]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  body = { status: status, error: Rack::Utils::HTTP_STATUS_CODES.fetch(status, Rack::Utils::HTTP_STATUS_CODES[500]) }
         
     | 
| 
       26 
30 
     | 
    
         | 
| 
       27 
31 
     | 
    
         
             
                  render(status, content_type, body)
         
     | 
| 
       28 
32 
     | 
    
         
             
                end
         
     | 
| 
         @@ -8,13 +8,13 @@ module ActionDispatch 
     | 
|
| 
       8 
8 
     | 
    
         
             
              # contain the address, and then picking the last-set address that is not
         
     | 
| 
       9 
9 
     | 
    
         
             
              # on the list of trusted IPs. This follows the precedent set by e.g.
         
     | 
| 
       10 
10 
     | 
    
         
             
              # {the Tomcat server}[https://issues.apache.org/bugzilla/show_bug.cgi?id=50453],
         
     | 
| 
       11 
     | 
    
         
            -
              # with {reasoning explained at length}[ 
     | 
| 
      
 11 
     | 
    
         
            +
              # with {reasoning explained at length}[https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection]
         
     | 
| 
       12 
12 
     | 
    
         
             
              # by @gingerlime. A more detailed explanation of the algorithm is given
         
     | 
| 
       13 
13 
     | 
    
         
             
              # at GetIp#calculate_ip.
         
     | 
| 
       14 
14 
     | 
    
         
             
              #
         
     | 
| 
       15 
15 
     | 
    
         
             
              # Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2]
         
     | 
| 
       16 
16 
     | 
    
         
             
              # requires. Some Rack servers simply drop preceding headers, and only report
         
     | 
| 
       17 
     | 
    
         
            -
              # the value that was {given in the last header}[ 
     | 
| 
      
 17 
     | 
    
         
            +
              # the value that was {given in the last header}[https://andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-servers].
         
     | 
| 
       18 
18 
     | 
    
         
             
              # If you are behind multiple proxy servers (like NGINX to HAProxy to Unicorn)
         
     | 
| 
       19 
19 
     | 
    
         
             
              # then you should test your Rack server to make sure your data is good.
         
     | 
| 
       20 
20 
     | 
    
         
             
              #
         
     | 
| 
         @@ -102,7 +102,7 @@ module ActionDispatch 
     | 
|
| 
       102 
102 
     | 
    
         
             
                  # proxies, that header may contain a list of IPs. Other proxy services
         
     | 
| 
       103 
103 
     | 
    
         
             
                  # set the Client-Ip header instead, so we check that too.
         
     | 
| 
       104 
104 
     | 
    
         
             
                  #
         
     | 
| 
       105 
     | 
    
         
            -
                  # As discussed in {this post about Rails IP Spoofing}[ 
     | 
| 
      
 105 
     | 
    
         
            +
                  # As discussed in {this post about Rails IP Spoofing}[https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/],
         
     | 
| 
       106 
106 
     | 
    
         
             
                  # while the first IP in the list is likely to be the "originating" IP,
         
     | 
| 
       107 
107 
     | 
    
         
             
                  # it could also have been set by the client maliciously.
         
     | 
| 
       108 
108 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -24,9 +24,10 @@ module ActionDispatch 
     | 
|
| 
       24 
24 
     | 
    
         
             
                #
         
     | 
| 
       25 
25 
     | 
    
         
             
                #   Rails.application.config.session_store :cookie_store, key: '_your_app_session'
         
     | 
| 
       26 
26 
     | 
    
         
             
                #
         
     | 
| 
       27 
     | 
    
         
            -
                #  
     | 
| 
       28 
     | 
    
         
            -
                #  
     | 
| 
       29 
     | 
    
         
            -
                # encrypted in the 
     | 
| 
      
 27 
     | 
    
         
            +
                # In the development and test environments your application's secret key base is
         
     | 
| 
      
 28 
     | 
    
         
            +
                # generated by Rails and stored in a temporary file in <tt>tmp/development_secret.txt</tt>.
         
     | 
| 
      
 29 
     | 
    
         
            +
                # In all other environments, it is stored encrypted in the
         
     | 
| 
      
 30 
     | 
    
         
            +
                # <tt>config/credentials.yml.enc</tt> file.
         
     | 
| 
       30 
31 
     | 
    
         
             
                #
         
     | 
| 
       31 
32 
     | 
    
         
             
                # If your application was not updated to Rails 5.2 defaults, the secret_key_base
         
     | 
| 
       32 
33 
     | 
    
         
             
                # will be found in the old <tt>config/secrets.yml</tt> file.
         
     | 
| 
         @@ -45,7 +45,7 @@ module ActionDispatch 
     | 
|
| 
       45 
45 
     | 
    
         
             
                    backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner"
         
     | 
| 
       46 
46 
     | 
    
         
             
                    wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
         
     | 
| 
       47 
47 
     | 
    
         
             
                    status  = wrapper.status_code
         
     | 
| 
       48 
     | 
    
         
            -
                    request.set_header "action_dispatch.exception", wrapper. 
     | 
| 
      
 48 
     | 
    
         
            +
                    request.set_header "action_dispatch.exception", wrapper.unwrapped_exception
         
     | 
| 
       49 
49 
     | 
    
         
             
                    request.set_header "action_dispatch.original_path", request.path_info
         
     | 
| 
       50 
50 
     | 
    
         
             
                    request.path_info = "/#{status}"
         
     | 
| 
       51 
51 
     | 
    
         
             
                    response = @exceptions_app.call(request.env)
         
     | 
| 
         @@ -36,6 +36,31 @@ module ActionDispatch 
     | 
|
| 
       36 
36 
     | 
    
         
             
                  def build(app)
         
     | 
| 
       37 
37 
     | 
    
         
             
                    klass.new(app, *args, &block)
         
     | 
| 
       38 
38 
     | 
    
         
             
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def build_instrumented(app)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    InstrumentationProxy.new(build(app), inspect)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # This class is used to instrument the execution of a single middleware.
         
     | 
| 
      
 46 
     | 
    
         
            +
                # It proxies the `call` method transparently and instruments the method
         
     | 
| 
      
 47 
     | 
    
         
            +
                # call.
         
     | 
| 
      
 48 
     | 
    
         
            +
                class InstrumentationProxy
         
     | 
| 
      
 49 
     | 
    
         
            +
                  EVENT_NAME = "process_middleware.action_dispatch"
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def initialize(middleware, class_name)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @middleware = middleware
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    @payload = {
         
     | 
| 
      
 55 
     | 
    
         
            +
                      middleware: class_name,
         
     | 
| 
      
 56 
     | 
    
         
            +
                    }
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  def call(env)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    ActiveSupport::Notifications.instrument(EVENT_NAME, @payload) do
         
     | 
| 
      
 61 
     | 
    
         
            +
                      @middleware.call(env)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
       39 
64 
     | 
    
         
             
                end
         
     | 
| 
       40 
65 
     | 
    
         | 
| 
       41 
66 
     | 
    
         
             
                include Enumerable
         
     | 
| 
         @@ -97,8 +122,15 @@ module ActionDispatch 
     | 
|
| 
       97 
122 
     | 
    
         
             
                  middlewares.push(build_middleware(klass, args, block))
         
     | 
| 
       98 
123 
     | 
    
         
             
                end
         
     | 
| 
       99 
124 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
                def build(app =  
     | 
| 
       101 
     | 
    
         
            -
                   
     | 
| 
      
 125 
     | 
    
         
            +
                def build(app = nil, &block)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  instrumenting = ActiveSupport::Notifications.notifier.listening?(InstrumentationProxy::EVENT_NAME)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  middlewares.freeze.reverse.inject(app || block) do |a, e|
         
     | 
| 
      
 128 
     | 
    
         
            +
                    if instrumenting
         
     | 
| 
      
 129 
     | 
    
         
            +
                      e.build_instrumented(a)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    else
         
     | 
| 
      
 131 
     | 
    
         
            +
                      e.build(a)
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
       102 
134 
     | 
    
         
             
                end
         
     | 
| 
       103 
135 
     | 
    
         | 
| 
       104 
136 
     | 
    
         
             
                private
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <% actions = ActiveSupport::ActionableError.actions(exception) %>
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            <% if actions.any? %>
         
     | 
| 
      
 4 
     | 
    
         
            +
              <div class="actions">
         
     | 
| 
      
 5 
     | 
    
         
            +
                <% actions.each do |action, _| %>
         
     | 
| 
      
 6 
     | 
    
         
            +
                  <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: {
         
     | 
| 
      
 7 
     | 
    
         
            +
                    error: exception.class.name,
         
     | 
| 
      
 8 
     | 
    
         
            +
                    action: action,
         
     | 
| 
      
 9 
     | 
    
         
            +
                    location: request.path
         
     | 
| 
      
 10 
     | 
    
         
            +
                  } %>
         
     | 
| 
      
 11 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 12 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 13 
     | 
    
         
            +
            <% end %>
         
     | 
| 
         
            File without changes
         
     | 
| 
         @@ -6,7 +6,9 @@ 
     | 
|
| 
       6 
6 
     | 
    
         
             
            <% end %>
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            <h2 style="margin-top: 30px">Request</h2>
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
            <% if params_valid? %>
         
     | 
| 
      
 10 
     | 
    
         
            +
              <p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
         
     | 
| 
      
 11 
     | 
    
         
            +
            <% end %>
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
            <div class="details">
         
     | 
| 
       12 
14 
     | 
    
         
             
              <div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
         
     | 
| 
         @@ -2,6 +2,6 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              <h1>Blocked host: <%= @host %></h1>
         
     | 
| 
       3 
3 
     | 
    
         
             
            </header>
         
     | 
| 
       4 
4 
     | 
    
         
             
            <div id="container">
         
     | 
| 
       5 
     | 
    
         
            -
              <h2>To allow requests to <%= @host %>, add the following configuration:</h2>
         
     | 
| 
       6 
     | 
    
         
            -
              <pre> 
     | 
| 
      
 5 
     | 
    
         
            +
              <h2>To allow requests to <%= @host %>, add the following to your environment configuration:</h2>
         
     | 
| 
      
 6 
     | 
    
         
            +
              <pre>config.hosts << "<%= @host %>"</pre>
         
     | 
| 
       7 
7 
     | 
    
         
             
            </div>
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Blocked host: <%= @host %>
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            To allow requests to <%= @host %>, add the following configuration:
         
     | 
| 
      
 3 
     | 
    
         
            +
            To allow requests to <%= @host %>, add the following to your environment configuration:
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              config.hosts << "<%= @host %>"
         
     | 
| 
         @@ -1,14 +1,18 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            <header>
         
     | 
| 
       2 
2 
     | 
    
         
             
              <h1>
         
     | 
| 
       3 
3 
     | 
    
         
             
                <%= @exception.class.to_s %>
         
     | 
| 
       4 
     | 
    
         
            -
                <% if @request.parameters['controller'] %>
         
     | 
| 
      
 4 
     | 
    
         
            +
                <% if params_valid? && @request.parameters['controller'] %>
         
     | 
| 
       5 
5 
     | 
    
         
             
                  in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
         
     | 
| 
       6 
6 
     | 
    
         
             
                <% end %>
         
     | 
| 
       7 
7 
     | 
    
         
             
              </h1>
         
     | 
| 
       8 
8 
     | 
    
         
             
            </header>
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            <div id="container">
         
     | 
| 
       11 
     | 
    
         
            -
              <h2 
     | 
| 
      
 11 
     | 
    
         
            +
              <h2>
         
     | 
| 
      
 12 
     | 
    
         
            +
                <%= h @exception.message %>
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                <%= render "rescues/actions", exception: @exception, request: @request %>
         
     | 
| 
      
 15 
     | 
    
         
            +
              </h2>
         
     | 
| 
       12 
16 
     | 
    
         | 
| 
       13 
17 
     | 
    
         
             
              <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %>
         
     | 
| 
       14 
18 
     | 
    
         
             
              <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %>
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            <%= @exception.class.to_s %><%
         
     | 
| 
       2 
     | 
    
         
            -
              if @request.parameters['controller']
         
     | 
| 
      
 2 
     | 
    
         
            +
              if params_valid? && @request.parameters['controller']
         
     | 
| 
       3 
3 
     | 
    
         
             
            %> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
         
     | 
| 
       4 
4 
     | 
    
         
             
            <% end %>
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
         @@ -10,9 +10,12 @@ 
     | 
|
| 
       10 
10 
     | 
    
         
             
            <div id="container">
         
     | 
| 
       11 
11 
     | 
    
         
             
              <h2>
         
     | 
| 
       12 
12 
     | 
    
         
             
                <%= h @exception.message %>
         
     | 
| 
       13 
     | 
    
         
            -
                <% if @exception.message.match? 
     | 
| 
      
 13 
     | 
    
         
            +
                <% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
         
     | 
| 
       14 
14 
     | 
    
         
             
                  <br />To resolve this issue run: rails active_storage:install
         
     | 
| 
       15 
15 
     | 
    
         
             
                <% end %>
         
     | 
| 
      
 16 
     | 
    
         
            +
                <% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
         
     | 
| 
      
 17 
     | 
    
         
            +
                  <br />To resolve this issue run: rails action_mailbox:install
         
     | 
| 
      
 18 
     | 
    
         
            +
                <% end %>
         
     | 
| 
       16 
19 
     | 
    
         
             
              </h2>
         
     | 
| 
       17 
20 
     | 
    
         | 
| 
       18 
21 
     | 
    
         
             
              <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
         
     | 
| 
         @@ -4,8 +4,10 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            <% end %>
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            <%= @exception.message %>
         
     | 
| 
       7 
     | 
    
         
            -
            <% if @exception.message.match? 
     | 
| 
      
 7 
     | 
    
         
            +
            <% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
         
     | 
| 
       8 
8 
     | 
    
         
             
            To resolve this issue run: rails active_storage:install
         
     | 
| 
      
 9 
     | 
    
         
            +
            <% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
         
     | 
| 
      
 10 
     | 
    
         
            +
            To resolve this issue run: rails action_mailbox:install
         
     | 
| 
       9 
11 
     | 
    
         
             
            <% end %>
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
            <%= render template: "rescues/_source" %>
         
     |