actionpack 6.0.3.6 → 6.1.0.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 +243 -251
 - data/MIT-LICENSE +1 -1
 - data/lib/abstract_controller.rb +1 -0
 - data/lib/abstract_controller/base.rb +35 -2
 - data/lib/abstract_controller/callbacks.rb +2 -2
 - data/lib/abstract_controller/helpers.rb +105 -90
 - data/lib/abstract_controller/rendering.rb +9 -9
 - data/lib/abstract_controller/translation.rb +8 -2
 - data/lib/action_controller.rb +2 -3
 - data/lib/action_controller/api.rb +2 -2
 - data/lib/action_controller/base.rb +4 -2
 - data/lib/action_controller/caching.rb +0 -1
 - data/lib/action_controller/log_subscriber.rb +3 -3
 - data/lib/action_controller/metal.rb +2 -2
 - data/lib/action_controller/metal/conditional_get.rb +10 -2
 - data/lib/action_controller/metal/content_security_policy.rb +1 -1
 - data/lib/action_controller/metal/data_streaming.rb +1 -1
 - data/lib/action_controller/metal/etag_with_template_digest.rb +2 -4
 - data/lib/action_controller/metal/exceptions.rb +33 -0
 - data/lib/action_controller/metal/feature_policy.rb +46 -0
 - data/lib/action_controller/metal/head.rb +7 -4
 - data/lib/action_controller/metal/helpers.rb +11 -1
 - data/lib/action_controller/metal/http_authentication.rb +4 -2
 - data/lib/action_controller/metal/implicit_render.rb +1 -1
 - data/lib/action_controller/metal/instrumentation.rb +11 -9
 - data/lib/action_controller/metal/live.rb +1 -1
 - data/lib/action_controller/metal/logging.rb +20 -0
 - data/lib/action_controller/metal/mime_responds.rb +6 -2
 - data/lib/action_controller/metal/parameter_encoding.rb +35 -4
 - data/lib/action_controller/metal/params_wrapper.rb +14 -8
 - data/lib/action_controller/metal/redirecting.rb +1 -1
 - data/lib/action_controller/metal/rendering.rb +6 -0
 - data/lib/action_controller/metal/request_forgery_protection.rb +48 -24
 - data/lib/action_controller/metal/rescue.rb +1 -1
 - data/lib/action_controller/metal/strong_parameters.rb +103 -15
 - data/lib/action_controller/renderer.rb +24 -13
 - data/lib/action_controller/test_case.rb +62 -56
 - data/lib/action_dispatch.rb +3 -2
 - data/lib/action_dispatch/http/cache.rb +12 -10
 - data/lib/action_dispatch/http/content_disposition.rb +2 -2
 - data/lib/action_dispatch/http/content_security_policy.rb +5 -1
 - data/lib/action_dispatch/http/feature_policy.rb +168 -0
 - data/lib/action_dispatch/http/filter_parameters.rb +1 -1
 - data/lib/action_dispatch/http/filter_redirect.rb +1 -1
 - data/lib/action_dispatch/http/headers.rb +3 -2
 - data/lib/action_dispatch/http/mime_negotiation.rb +20 -8
 - data/lib/action_dispatch/http/mime_type.rb +28 -15
 - data/lib/action_dispatch/http/parameters.rb +1 -19
 - data/lib/action_dispatch/http/request.rb +26 -8
 - data/lib/action_dispatch/http/response.rb +17 -16
 - data/lib/action_dispatch/http/url.rb +3 -2
 - data/lib/action_dispatch/journey.rb +0 -2
 - data/lib/action_dispatch/journey/formatter.rb +53 -28
 - data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
 - data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
 - data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
 - data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
 - data/lib/action_dispatch/journey/nodes/node.rb +4 -3
 - data/lib/action_dispatch/journey/parser.rb +13 -13
 - data/lib/action_dispatch/journey/parser.y +1 -1
 - data/lib/action_dispatch/journey/path/pattern.rb +13 -18
 - data/lib/action_dispatch/journey/route.rb +7 -18
 - data/lib/action_dispatch/journey/router.rb +26 -30
 - data/lib/action_dispatch/journey/router/utils.rb +6 -4
 - data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -2
 - data/lib/action_dispatch/middleware/cookies.rb +74 -33
 - data/lib/action_dispatch/middleware/debug_exceptions.rb +10 -17
 - data/lib/action_dispatch/middleware/debug_view.rb +1 -1
 - data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -17
 - data/lib/action_dispatch/middleware/host_authorization.rb +28 -17
 - data/lib/action_dispatch/middleware/public_exceptions.rb +1 -1
 - data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
 - data/lib/action_dispatch/middleware/request_id.rb +4 -5
 - data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
 - data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
 - data/lib/action_dispatch/middleware/ssl.rb +9 -6
 - data/lib/action_dispatch/middleware/stack.rb +18 -0
 - data/lib/action_dispatch/middleware/static.rb +154 -93
 - data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +18 -0
 - data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
 - data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
 - data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
 - data/lib/action_dispatch/middleware/templates/rescues/layout.erb +88 -8
 - data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
 - data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +12 -1
 - data/lib/action_dispatch/railtie.rb +3 -2
 - data/lib/action_dispatch/request/session.rb +2 -8
 - data/lib/action_dispatch/request/utils.rb +26 -2
 - data/lib/action_dispatch/routing/inspector.rb +8 -7
 - data/lib/action_dispatch/routing/mapper.rb +102 -71
 - data/lib/action_dispatch/routing/polymorphic_routes.rb +12 -11
 - data/lib/action_dispatch/routing/redirection.rb +3 -3
 - data/lib/action_dispatch/routing/route_set.rb +49 -41
 - data/lib/action_dispatch/routing/url_for.rb +1 -0
 - data/lib/action_dispatch/system_test_case.rb +29 -24
 - data/lib/action_dispatch/system_testing/browser.rb +33 -27
 - data/lib/action_dispatch/system_testing/driver.rb +6 -7
 - data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
 - data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
 - data/lib/action_dispatch/testing/assertions.rb +1 -1
 - data/lib/action_dispatch/testing/assertions/response.rb +2 -4
 - data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
 - data/lib/action_dispatch/testing/integration.rb +38 -27
 - data/lib/action_dispatch/testing/test_process.rb +29 -4
 - data/lib/action_dispatch/testing/test_request.rb +3 -3
 - data/lib/action_pack.rb +1 -1
 - data/lib/action_pack/gem_version.rb +3 -3
 - metadata +20 -21
 - data/lib/action_controller/metal/force_ssl.rb +0 -58
 - data/lib/action_dispatch/http/parameter_filter.rb +0 -12
 - data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
 - data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
 - data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
 
| 
         @@ -65,7 +65,7 @@ module ActionController 
     | 
|
| 
       65 
65 
     | 
    
         
             
                def initialize(controller, env, defaults)
         
     | 
| 
       66 
66 
     | 
    
         
             
                  @controller = controller
         
     | 
| 
       67 
67 
     | 
    
         
             
                  @defaults = defaults
         
     | 
| 
       68 
     | 
    
         
            -
                  @env = normalize_keys defaults 
     | 
| 
      
 68 
     | 
    
         
            +
                  @env = normalize_keys defaults, env
         
     | 
| 
       69 
69 
     | 
    
         
             
                end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                # Render templates with any options from ActionController::Base#render_to_string.
         
     | 
| 
         @@ -82,8 +82,12 @@ module ActionController 
     | 
|
| 
       82 
82 
     | 
    
         
             
                #   need to call <tt>.to_json</tt> on the object you want to render.
         
     | 
| 
       83 
83 
     | 
    
         
             
                # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
         
     | 
| 
       84 
84 
     | 
    
         
             
                #
         
     | 
| 
       85 
     | 
    
         
            -
                # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified,  
     | 
| 
       86 
     | 
    
         
            -
                # 
     | 
| 
      
 85 
     | 
    
         
            +
                # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
         
     | 
| 
      
 86 
     | 
    
         
            +
                #
         
     | 
| 
      
 87 
     | 
    
         
            +
                # If an object responding to `render_in` is passed, `render_in` is called on the object,
         
     | 
| 
      
 88 
     | 
    
         
            +
                # passing in the current view context.
         
     | 
| 
      
 89 
     | 
    
         
            +
                #
         
     | 
| 
      
 90 
     | 
    
         
            +
                # Otherwise, a partial is rendered using the second parameter as the locals hash.
         
     | 
| 
       87 
91 
     | 
    
         
             
                def render(*args)
         
     | 
| 
       88 
92 
     | 
    
         
             
                  raise "missing controller" unless controller
         
     | 
| 
       89 
93 
     | 
    
         | 
| 
         @@ -95,11 +99,18 @@ module ActionController 
     | 
|
| 
       95 
99 
     | 
    
         
             
                  instance.set_response! controller.make_response!(request)
         
     | 
| 
       96 
100 
     | 
    
         
             
                  instance.render_to_string(*args)
         
     | 
| 
       97 
101 
     | 
    
         
             
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
                alias_method :render_to_string, :render # :nodoc:
         
     | 
| 
       98 
103 
     | 
    
         | 
| 
       99 
104 
     | 
    
         
             
                private
         
     | 
| 
       100 
     | 
    
         
            -
                  def normalize_keys(env)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  def normalize_keys(defaults, env)
         
     | 
| 
       101 
106 
     | 
    
         
             
                    new_env = {}
         
     | 
| 
       102 
107 
     | 
    
         
             
                    env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                    defaults.each_pair do |k, v|
         
     | 
| 
      
 110 
     | 
    
         
            +
                      key = rack_key_for(k)
         
     | 
| 
      
 111 
     | 
    
         
            +
                      new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
       103 
114 
     | 
    
         
             
                    new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
         
     | 
| 
       104 
115 
     | 
    
         
             
                    new_env
         
     | 
| 
       105 
116 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -112,19 +123,19 @@ module ActionController 
     | 
|
| 
       112 
123 
     | 
    
         
             
                    input:       "rack.input"
         
     | 
| 
       113 
124 
     | 
    
         
             
                  }
         
     | 
| 
       114 
125 
     | 
    
         | 
| 
       115 
     | 
    
         
            -
                  IDENTITY = ->(_) { _ }
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                  RACK_VALUE_TRANSLATION = {
         
     | 
| 
       118 
     | 
    
         
            -
                    https: ->(v) { v ? "on" : "off" },
         
     | 
| 
       119 
     | 
    
         
            -
                    method: ->(v) { -v.upcase },
         
     | 
| 
       120 
     | 
    
         
            -
                  }
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
126 
     | 
    
         
             
                  def rack_key_for(key)
         
     | 
| 
       123 
     | 
    
         
            -
                    RACK_KEY_TRANSLATION 
     | 
| 
      
 127 
     | 
    
         
            +
                    RACK_KEY_TRANSLATION[key] || key.to_s
         
     | 
| 
       124 
128 
     | 
    
         
             
                  end
         
     | 
| 
       125 
129 
     | 
    
         | 
| 
       126 
130 
     | 
    
         
             
                  def rack_value_for(key, value)
         
     | 
| 
       127 
     | 
    
         
            -
                     
     | 
| 
      
 131 
     | 
    
         
            +
                    case key
         
     | 
| 
      
 132 
     | 
    
         
            +
                    when :https
         
     | 
| 
      
 133 
     | 
    
         
            +
                      value ? "on" : "off"
         
     | 
| 
      
 134 
     | 
    
         
            +
                    when :method
         
     | 
| 
      
 135 
     | 
    
         
            +
                      -value.upcase
         
     | 
| 
      
 136 
     | 
    
         
            +
                    else
         
     | 
| 
      
 137 
     | 
    
         
            +
                      value
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
       128 
139 
     | 
    
         
             
                  end
         
     | 
| 
       129 
140 
     | 
    
         
             
              end
         
     | 
| 
       130 
141 
     | 
    
         
             
            end
         
     | 
| 
         @@ -84,7 +84,7 @@ module ActionController 
     | 
|
| 
       84 
84 
     | 
    
         
             
                        value = value.to_param
         
     | 
| 
       85 
85 
     | 
    
         
             
                      end
         
     | 
| 
       86 
86 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
                      path_parameters[key] = value
         
     | 
| 
      
 87 
     | 
    
         
            +
                      path_parameters[key.to_sym] = value
         
     | 
| 
       88 
88 
     | 
    
         
             
                    end
         
     | 
| 
       89 
89 
     | 
    
         
             
                  end
         
     | 
| 
       90 
90 
     | 
    
         | 
| 
         @@ -492,57 +492,8 @@ module ActionController 
     | 
|
| 
       492 
492 
     | 
    
         
             
                      parameters[:format] = format
         
     | 
| 
       493 
493 
     | 
    
         
             
                    end
         
     | 
| 
       494 
494 
     | 
    
         | 
| 
       495 
     | 
    
         
            -
                     
     | 
| 
       496 
     | 
    
         
            -
                     
     | 
| 
       497 
     | 
    
         
            -
                    query_string_keys = query_parameter_names(generated_extras)
         
     | 
| 
       498 
     | 
    
         
            -
             
     | 
| 
       499 
     | 
    
         
            -
                    @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
         
     | 
| 
       500 
     | 
    
         
            -
             
     | 
| 
       501 
     | 
    
         
            -
                    @request.session.update(session) if session
         
     | 
| 
       502 
     | 
    
         
            -
                    @request.flash.update(flash || {})
         
     | 
| 
       503 
     | 
    
         
            -
             
     | 
| 
       504 
     | 
    
         
            -
                    if xhr
         
     | 
| 
       505 
     | 
    
         
            -
                      @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
         
     | 
| 
       506 
     | 
    
         
            -
                      @request.fetch_header("HTTP_ACCEPT") do |k|
         
     | 
| 
       507 
     | 
    
         
            -
                        @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
         
     | 
| 
       508 
     | 
    
         
            -
                      end
         
     | 
| 
       509 
     | 
    
         
            -
                    end
         
     | 
| 
       510 
     | 
    
         
            -
             
     | 
| 
       511 
     | 
    
         
            -
                    @request.fetch_header("SCRIPT_NAME") do |k|
         
     | 
| 
       512 
     | 
    
         
            -
                      @request.set_header k, @controller.config.relative_url_root
         
     | 
| 
       513 
     | 
    
         
            -
                    end
         
     | 
| 
       514 
     | 
    
         
            -
             
     | 
| 
       515 
     | 
    
         
            -
                    begin
         
     | 
| 
       516 
     | 
    
         
            -
                      @controller.recycle!
         
     | 
| 
       517 
     | 
    
         
            -
                      @controller.dispatch(action, @request, @response)
         
     | 
| 
       518 
     | 
    
         
            -
                    ensure
         
     | 
| 
       519 
     | 
    
         
            -
                      @request = @controller.request
         
     | 
| 
       520 
     | 
    
         
            -
                      @response = @controller.response
         
     | 
| 
       521 
     | 
    
         
            -
             
     | 
| 
       522 
     | 
    
         
            -
                      if @request.have_cookie_jar?
         
     | 
| 
       523 
     | 
    
         
            -
                        unless @request.cookie_jar.committed?
         
     | 
| 
       524 
     | 
    
         
            -
                          @request.cookie_jar.write(@response)
         
     | 
| 
       525 
     | 
    
         
            -
                          cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
         
     | 
| 
       526 
     | 
    
         
            -
                        end
         
     | 
| 
       527 
     | 
    
         
            -
                      end
         
     | 
| 
       528 
     | 
    
         
            -
                      @response.prepare!
         
     | 
| 
       529 
     | 
    
         
            -
             
     | 
| 
       530 
     | 
    
         
            -
                      if flash_value = @request.flash.to_session_value
         
     | 
| 
       531 
     | 
    
         
            -
                        @request.session["flash"] = flash_value
         
     | 
| 
       532 
     | 
    
         
            -
                      else
         
     | 
| 
       533 
     | 
    
         
            -
                        @request.session.delete("flash")
         
     | 
| 
       534 
     | 
    
         
            -
                      end
         
     | 
| 
       535 
     | 
    
         
            -
             
     | 
| 
       536 
     | 
    
         
            -
                      if xhr
         
     | 
| 
       537 
     | 
    
         
            -
                        @request.delete_header "HTTP_X_REQUESTED_WITH"
         
     | 
| 
       538 
     | 
    
         
            -
                        @request.delete_header "HTTP_ACCEPT"
         
     | 
| 
       539 
     | 
    
         
            -
                      end
         
     | 
| 
       540 
     | 
    
         
            -
                      @request.query_string = ""
         
     | 
| 
       541 
     | 
    
         
            -
             
     | 
| 
       542 
     | 
    
         
            -
                      @response.sent!
         
     | 
| 
       543 
     | 
    
         
            -
                    end
         
     | 
| 
       544 
     | 
    
         
            -
             
     | 
| 
       545 
     | 
    
         
            -
                    @response
         
     | 
| 
      
 495 
     | 
    
         
            +
                    setup_request(controller_class_name, action, parameters, session, flash, xhr)
         
     | 
| 
      
 496 
     | 
    
         
            +
                    process_controller_response(action, cookies, xhr)
         
     | 
| 
       546 
497 
     | 
    
         
             
                  end
         
     | 
| 
       547 
498 
     | 
    
         | 
| 
       548 
499 
     | 
    
         
             
                  def controller_class_name
         
     | 
| 
         @@ -598,11 +549,66 @@ module ActionController 
     | 
|
| 
       598 
549 
     | 
    
         
             
                  end
         
     | 
| 
       599 
550 
     | 
    
         | 
| 
       600 
551 
     | 
    
         
             
                  private
         
     | 
| 
      
 552 
     | 
    
         
            +
                    def setup_request(controller_class_name, action, parameters, session, flash, xhr)
         
     | 
| 
      
 553 
     | 
    
         
            +
                      generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
         
     | 
| 
      
 554 
     | 
    
         
            +
                      generated_path = generated_path(generated_extras)
         
     | 
| 
      
 555 
     | 
    
         
            +
                      query_string_keys = query_parameter_names(generated_extras)
         
     | 
| 
      
 556 
     | 
    
         
            +
             
     | 
| 
      
 557 
     | 
    
         
            +
                      @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
         
     | 
| 
      
 558 
     | 
    
         
            +
             
     | 
| 
      
 559 
     | 
    
         
            +
                      @request.session.update(session) if session
         
     | 
| 
      
 560 
     | 
    
         
            +
                      @request.flash.update(flash || {})
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
      
 562 
     | 
    
         
            +
                      if xhr
         
     | 
| 
      
 563 
     | 
    
         
            +
                        @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
         
     | 
| 
      
 564 
     | 
    
         
            +
                        @request.fetch_header("HTTP_ACCEPT") do |k|
         
     | 
| 
      
 565 
     | 
    
         
            +
                          @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
         
     | 
| 
      
 566 
     | 
    
         
            +
                        end
         
     | 
| 
      
 567 
     | 
    
         
            +
                      end
         
     | 
| 
      
 568 
     | 
    
         
            +
             
     | 
| 
      
 569 
     | 
    
         
            +
                      @request.fetch_header("SCRIPT_NAME") do |k|
         
     | 
| 
      
 570 
     | 
    
         
            +
                        @request.set_header k, @controller.config.relative_url_root
         
     | 
| 
      
 571 
     | 
    
         
            +
                      end
         
     | 
| 
      
 572 
     | 
    
         
            +
                    end
         
     | 
| 
      
 573 
     | 
    
         
            +
             
     | 
| 
      
 574 
     | 
    
         
            +
                    def process_controller_response(action, cookies, xhr)
         
     | 
| 
      
 575 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 576 
     | 
    
         
            +
                        @controller.recycle!
         
     | 
| 
      
 577 
     | 
    
         
            +
                        @controller.dispatch(action, @request, @response)
         
     | 
| 
      
 578 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 579 
     | 
    
         
            +
                        @request = @controller.request
         
     | 
| 
      
 580 
     | 
    
         
            +
                        @response = @controller.response
         
     | 
| 
      
 581 
     | 
    
         
            +
             
     | 
| 
      
 582 
     | 
    
         
            +
                        if @request.have_cookie_jar?
         
     | 
| 
      
 583 
     | 
    
         
            +
                          unless @request.cookie_jar.committed?
         
     | 
| 
      
 584 
     | 
    
         
            +
                            @request.cookie_jar.write(@response)
         
     | 
| 
      
 585 
     | 
    
         
            +
                            cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
         
     | 
| 
      
 586 
     | 
    
         
            +
                          end
         
     | 
| 
      
 587 
     | 
    
         
            +
                        end
         
     | 
| 
      
 588 
     | 
    
         
            +
                        @response.prepare!
         
     | 
| 
      
 589 
     | 
    
         
            +
             
     | 
| 
      
 590 
     | 
    
         
            +
                        if flash_value = @request.flash.to_session_value
         
     | 
| 
      
 591 
     | 
    
         
            +
                          @request.session["flash"] = flash_value
         
     | 
| 
      
 592 
     | 
    
         
            +
                        else
         
     | 
| 
      
 593 
     | 
    
         
            +
                          @request.session.delete("flash")
         
     | 
| 
      
 594 
     | 
    
         
            +
                        end
         
     | 
| 
      
 595 
     | 
    
         
            +
             
     | 
| 
      
 596 
     | 
    
         
            +
                        if xhr
         
     | 
| 
      
 597 
     | 
    
         
            +
                          @request.delete_header "HTTP_X_REQUESTED_WITH"
         
     | 
| 
      
 598 
     | 
    
         
            +
                          @request.delete_header "HTTP_ACCEPT"
         
     | 
| 
      
 599 
     | 
    
         
            +
                        end
         
     | 
| 
      
 600 
     | 
    
         
            +
                        @request.query_string = ""
         
     | 
| 
      
 601 
     | 
    
         
            +
             
     | 
| 
      
 602 
     | 
    
         
            +
                        @response.sent!
         
     | 
| 
      
 603 
     | 
    
         
            +
                      end
         
     | 
| 
      
 604 
     | 
    
         
            +
             
     | 
| 
      
 605 
     | 
    
         
            +
                      @response
         
     | 
| 
      
 606 
     | 
    
         
            +
                    end
         
     | 
| 
      
 607 
     | 
    
         
            +
             
     | 
| 
       601 
608 
     | 
    
         
             
                    def scrub_env!(env)
         
     | 
| 
       602 
     | 
    
         
            -
                      env.delete_if  
     | 
| 
       603 
     | 
    
         
            -
             
     | 
| 
       604 
     | 
    
         
            -
                       
     | 
| 
       605 
     | 
    
         
            -
                      env.delete "action_dispatch.request.request_parameters"
         
     | 
| 
      
 609 
     | 
    
         
            +
                      env.delete_if do |k, _|
         
     | 
| 
      
 610 
     | 
    
         
            +
                        k.start_with?("rack.request", "action_dispatch.request", "action_dispatch.rescue")
         
     | 
| 
      
 611 
     | 
    
         
            +
                      end
         
     | 
| 
       606 
612 
     | 
    
         
             
                      env["rack.input"] = StringIO.new
         
     | 
| 
       607 
613 
     | 
    
         
             
                      env.delete "CONTENT_LENGTH"
         
     | 
| 
       608 
614 
     | 
    
         
             
                      env.delete "RAW_POST_DATA"
         
     | 
    
        data/lib/action_dispatch.rb
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            #--
         
     | 
| 
       4 
     | 
    
         
            -
            # Copyright (c) 2004- 
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright (c) 2004-2020 David Heinemeier Hansson
         
     | 
| 
       5 
5 
     | 
    
         
             
            #
         
     | 
| 
       6 
6 
     | 
    
         
             
            # Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
       7 
7 
     | 
    
         
             
            # a copy of this software and associated documentation files (the
         
     | 
| 
         @@ -46,6 +46,7 @@ module ActionDispatch 
     | 
|
| 
       46 
46 
     | 
    
         
             
              eager_autoload do
         
     | 
| 
       47 
47 
     | 
    
         
             
                autoload_under "http" do
         
     | 
| 
       48 
48 
     | 
    
         
             
                  autoload :ContentSecurityPolicy
         
     | 
| 
      
 49 
     | 
    
         
            +
                  autoload :FeaturePolicy
         
     | 
| 
       49 
50 
     | 
    
         
             
                  autoload :Request
         
     | 
| 
       50 
51 
     | 
    
         
             
                  autoload :Response
         
     | 
| 
       51 
52 
     | 
    
         
             
                end
         
     | 
| 
         @@ -82,7 +83,6 @@ module ActionDispatch 
     | 
|
| 
       82 
83 
     | 
    
         
             
                autoload :Headers
         
     | 
| 
       83 
84 
     | 
    
         
             
                autoload :MimeNegotiation
         
     | 
| 
       84 
85 
     | 
    
         
             
                autoload :Parameters
         
     | 
| 
       85 
     | 
    
         
            -
                autoload :ParameterFilter
         
     | 
| 
       86 
86 
     | 
    
         
             
                autoload :UploadedFile, "action_dispatch/http/upload"
         
     | 
| 
       87 
87 
     | 
    
         
             
                autoload :URL
         
     | 
| 
       88 
88 
     | 
    
         
             
              end
         
     | 
| 
         @@ -115,4 +115,5 @@ autoload :Mime, "action_dispatch/http/mime_type" 
     | 
|
| 
       115 
115 
     | 
    
         
             
            ActiveSupport.on_load(:action_view) do
         
     | 
| 
       116 
116 
     | 
    
         
             
              ActionView::Base.default_formats ||= Mime::SET.symbols
         
     | 
| 
       117 
117 
     | 
    
         
             
              ActionView::Template::Types.delegate_to Mime
         
     | 
| 
      
 118 
     | 
    
         
            +
              ActionView::LookupContext::DetailsKey.clear
         
     | 
| 
       118 
119 
     | 
    
         
             
            end
         
     | 
| 
         @@ -114,7 +114,7 @@ module ActionDispatch 
     | 
|
| 
       114 
114 
     | 
    
         | 
| 
       115 
115 
     | 
    
         
             
                    # True if an ETag is set and it's a weak validator (preceded with W/)
         
     | 
| 
       116 
116 
     | 
    
         
             
                    def weak_etag?
         
     | 
| 
       117 
     | 
    
         
            -
                      etag? && etag. 
     | 
| 
      
 117 
     | 
    
         
            +
                      etag? && etag.start_with?('W/"')
         
     | 
| 
       118 
118 
     | 
    
         
             
                    end
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
       120 
120 
     | 
    
         
             
                    # True if an ETag is set and it isn't a weak validator (not preceded with W/)
         
     | 
| 
         @@ -125,7 +125,7 @@ module ActionDispatch 
     | 
|
| 
       125 
125 
     | 
    
         
             
                  private
         
     | 
| 
       126 
126 
     | 
    
         
             
                    DATE          = "Date"
         
     | 
| 
       127 
127 
     | 
    
         
             
                    LAST_MODIFIED = "Last-Modified"
         
     | 
| 
       128 
     | 
    
         
            -
                    SPECIAL_KEYS  = Set.new(%w[extras no-cache max-age public private must-revalidate])
         
     | 
| 
      
 128 
     | 
    
         
            +
                    SPECIAL_KEYS  = Set.new(%w[extras no-store no-cache max-age public private must-revalidate])
         
     | 
| 
       129 
129 
     | 
    
         | 
| 
       130 
130 
     | 
    
         
             
                    def generate_weak_etag(validators)
         
     | 
| 
       131 
131 
     | 
    
         
             
                      "W/#{generate_strong_etag(validators)}"
         
     | 
| 
         @@ -150,8 +150,8 @@ module ActionDispatch 
     | 
|
| 
       150 
150 
     | 
    
         
             
                        directive, argument = segment.split("=", 2)
         
     | 
| 
       151 
151 
     | 
    
         | 
| 
       152 
152 
     | 
    
         
             
                        if SPECIAL_KEYS.include? directive
         
     | 
| 
       153 
     | 
    
         
            -
                           
     | 
| 
       154 
     | 
    
         
            -
                          cache_control[ 
     | 
| 
      
 153 
     | 
    
         
            +
                          directive.tr!("-", "_")
         
     | 
| 
      
 154 
     | 
    
         
            +
                          cache_control[directive.to_sym] = argument || true
         
     | 
| 
       155 
155 
     | 
    
         
             
                        else
         
     | 
| 
       156 
156 
     | 
    
         
             
                          cache_control[:extras] ||= []
         
     | 
| 
       157 
157 
     | 
    
         
             
                          cache_control[:extras] << segment
         
     | 
| 
         @@ -166,6 +166,7 @@ module ActionDispatch 
     | 
|
| 
       166 
166 
     | 
    
         
             
                    end
         
     | 
| 
       167 
167 
     | 
    
         | 
| 
       168 
168 
     | 
    
         
             
                    DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
         
     | 
| 
      
 169 
     | 
    
         
            +
                    NO_STORE              = "no-store"
         
     | 
| 
       169 
170 
     | 
    
         
             
                    NO_CACHE              = "no-cache"
         
     | 
| 
       170 
171 
     | 
    
         
             
                    PUBLIC                = "public"
         
     | 
| 
       171 
172 
     | 
    
         
             
                    PRIVATE               = "private"
         
     | 
| 
         @@ -182,19 +183,20 @@ module ActionDispatch 
     | 
|
| 
       182 
183 
     | 
    
         
             
                    end
         
     | 
| 
       183 
184 
     | 
    
         | 
| 
       184 
185 
     | 
    
         
             
                    def merge_and_normalize_cache_control!(cache_control)
         
     | 
| 
       185 
     | 
    
         
            -
                      control =  
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                      if  
     | 
| 
      
 186 
     | 
    
         
            +
                      control = cache_control_headers
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                      return if control.empty? && cache_control.empty?  # Let middleware handle default behavior
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                      if extras = control.delete(:extras)
         
     | 
| 
       188 
191 
     | 
    
         
             
                        cache_control[:extras] ||= []
         
     | 
| 
       189 
192 
     | 
    
         
             
                        cache_control[:extras] += extras
         
     | 
| 
       190 
193 
     | 
    
         
             
                        cache_control[:extras].uniq!
         
     | 
| 
       191 
194 
     | 
    
         
             
                      end
         
     | 
| 
       192 
195 
     | 
    
         | 
| 
       193 
     | 
    
         
            -
                      control.merge! cc_headers
         
     | 
| 
       194 
196 
     | 
    
         
             
                      control.merge! cache_control
         
     | 
| 
       195 
197 
     | 
    
         | 
| 
       196 
     | 
    
         
            -
                      if control 
     | 
| 
       197 
     | 
    
         
            -
                         
     | 
| 
      
 198 
     | 
    
         
            +
                      if control[:no_store]
         
     | 
| 
      
 199 
     | 
    
         
            +
                        self._cache_control = NO_STORE
         
     | 
| 
       198 
200 
     | 
    
         
             
                      elsif control[:no_cache]
         
     | 
| 
       199 
201 
     | 
    
         
             
                        options = []
         
     | 
| 
       200 
202 
     | 
    
         
             
                        options << PUBLIC if control[:public]
         
     | 
| 
         @@ -14,13 +14,13 @@ module ActionDispatch 
     | 
|
| 
       14 
14 
     | 
    
         
             
                    @filename = filename
         
     | 
| 
       15 
15 
     | 
    
         
             
                  end
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                  TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9 
     | 
| 
      
 17 
     | 
    
         
            +
                  TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!\#$+.^_`|~-]/
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                  def ascii_filename
         
     | 
| 
       20 
20 
     | 
    
         
             
                    'filename="' + percent_escape(I18n.transliterate(filename), TRADITIONAL_ESCAPED_CHAR) + '"'
         
     | 
| 
       21 
21 
     | 
    
         
             
                  end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
                  RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9 
     | 
| 
      
 23 
     | 
    
         
            +
                  RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!\#$&+.^_`|~-]/
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                  def utf8_filename
         
     | 
| 
       26 
26 
     | 
    
         
             
                    "filename*=UTF-8''" + percent_escape(filename, RFC_5987_ESCAPED_CHAR)
         
     | 
| 
         @@ -33,7 +33,7 @@ module ActionDispatch #:nodoc: 
     | 
|
| 
       33 
33 
     | 
    
         
             
                  private
         
     | 
| 
       34 
34 
     | 
    
         
             
                    def html_response?(headers)
         
     | 
| 
       35 
35 
     | 
    
         
             
                      if content_type = headers[CONTENT_TYPE]
         
     | 
| 
       36 
     | 
    
         
            -
                         
     | 
| 
      
 36 
     | 
    
         
            +
                        /html/.match?(content_type)
         
     | 
| 
       37 
37 
     | 
    
         
             
                      end
         
     | 
| 
       38 
38 
     | 
    
         
             
                    end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
         @@ -137,7 +137,11 @@ module ActionDispatch #:nodoc: 
     | 
|
| 
       137 
137 
     | 
    
         
             
                  object_src:      "object-src",
         
     | 
| 
       138 
138 
     | 
    
         
             
                  prefetch_src:    "prefetch-src",
         
     | 
| 
       139 
139 
     | 
    
         
             
                  script_src:      "script-src",
         
     | 
| 
      
 140 
     | 
    
         
            +
                  script_src_attr: "script-src-attr",
         
     | 
| 
      
 141 
     | 
    
         
            +
                  script_src_elem: "script-src-elem",
         
     | 
| 
       140 
142 
     | 
    
         
             
                  style_src:       "style-src",
         
     | 
| 
      
 143 
     | 
    
         
            +
                  style_src_attr:  "style-src-attr",
         
     | 
| 
      
 144 
     | 
    
         
            +
                  style_src_elem:  "style-src-elem",
         
     | 
| 
       141 
145 
     | 
    
         
             
                  worker_src:      "worker-src"
         
     | 
| 
       142 
146 
     | 
    
         
             
                }.freeze
         
     | 
| 
       143 
147 
     | 
    
         | 
| 
         @@ -0,0 +1,168 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_support/core_ext/object/deep_dup"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module ActionDispatch #:nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
              class FeaturePolicy
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Middleware
         
     | 
| 
      
 8 
     | 
    
         
            +
                  CONTENT_TYPE = "Content-Type"
         
     | 
| 
      
 9 
     | 
    
         
            +
                  POLICY       = "Feature-Policy"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def initialize(app)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @app = app
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def call(env)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    request = ActionDispatch::Request.new(env)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    _, headers, _ = response = @app.call(env)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    return response unless html_response?(headers)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    return response if policy_present?(headers)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    if policy = request.feature_policy
         
     | 
| 
      
 23 
     | 
    
         
            +
                      headers[POLICY] = policy.build(request.controller_instance)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    if policy_empty?(policy)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      headers.delete(POLICY)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    response
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  private
         
     | 
| 
      
 34 
     | 
    
         
            +
                    def html_response?(headers)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      if content_type = headers[CONTENT_TYPE]
         
     | 
| 
      
 36 
     | 
    
         
            +
                        /html/.match?(content_type)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      end
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    def policy_present?(headers)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      headers[POLICY]
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    def policy_empty?(policy)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      policy&.directives&.empty?
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                module Request
         
     | 
| 
      
 50 
     | 
    
         
            +
                  POLICY = "action_dispatch.feature_policy"
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  def feature_policy
         
     | 
| 
      
 53 
     | 
    
         
            +
                    get_header(POLICY)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  def feature_policy=(policy)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    set_header(POLICY, policy)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                MAPPINGS = {
         
     | 
| 
      
 62 
     | 
    
         
            +
                  self: "'self'",
         
     | 
| 
      
 63 
     | 
    
         
            +
                  none: "'none'",
         
     | 
| 
      
 64 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                # List of available features can be found at
         
     | 
| 
      
 67 
     | 
    
         
            +
                # https://github.com/WICG/feature-policy/blob/master/features.md#policy-controlled-features
         
     | 
| 
      
 68 
     | 
    
         
            +
                DIRECTIVES = {
         
     | 
| 
      
 69 
     | 
    
         
            +
                  accelerometer:        "accelerometer",
         
     | 
| 
      
 70 
     | 
    
         
            +
                  ambient_light_sensor: "ambient-light-sensor",
         
     | 
| 
      
 71 
     | 
    
         
            +
                  autoplay:             "autoplay",
         
     | 
| 
      
 72 
     | 
    
         
            +
                  camera:               "camera",
         
     | 
| 
      
 73 
     | 
    
         
            +
                  encrypted_media:      "encrypted-media",
         
     | 
| 
      
 74 
     | 
    
         
            +
                  fullscreen:           "fullscreen",
         
     | 
| 
      
 75 
     | 
    
         
            +
                  geolocation:          "geolocation",
         
     | 
| 
      
 76 
     | 
    
         
            +
                  gyroscope:            "gyroscope",
         
     | 
| 
      
 77 
     | 
    
         
            +
                  magnetometer:         "magnetometer",
         
     | 
| 
      
 78 
     | 
    
         
            +
                  microphone:           "microphone",
         
     | 
| 
      
 79 
     | 
    
         
            +
                  midi:                 "midi",
         
     | 
| 
      
 80 
     | 
    
         
            +
                  payment:              "payment",
         
     | 
| 
      
 81 
     | 
    
         
            +
                  picture_in_picture:   "picture-in-picture",
         
     | 
| 
      
 82 
     | 
    
         
            +
                  speaker:              "speaker",
         
     | 
| 
      
 83 
     | 
    
         
            +
                  usb:                  "usb",
         
     | 
| 
      
 84 
     | 
    
         
            +
                  vibrate:              "vibrate",
         
     | 
| 
      
 85 
     | 
    
         
            +
                  vr:                   "vr",
         
     | 
| 
      
 86 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                private_constant :MAPPINGS, :DIRECTIVES
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                attr_reader :directives
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @directives = {}
         
     | 
| 
      
 94 
     | 
    
         
            +
                  yield self if block_given?
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                def initialize_copy(other)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  @directives = other.directives.deep_dup
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                DIRECTIVES.each do |name, directive|
         
     | 
| 
      
 102 
     | 
    
         
            +
                  define_method(name) do |*sources|
         
     | 
| 
      
 103 
     | 
    
         
            +
                    if sources.first
         
     | 
| 
      
 104 
     | 
    
         
            +
                      @directives[directive] = apply_mappings(sources)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    else
         
     | 
| 
      
 106 
     | 
    
         
            +
                      @directives.delete(directive)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                def build(context = nil)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  build_directives(context).compact.join("; ")
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                private
         
     | 
| 
      
 116 
     | 
    
         
            +
                  def apply_mappings(sources)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    sources.map do |source|
         
     | 
| 
      
 118 
     | 
    
         
            +
                      case source
         
     | 
| 
      
 119 
     | 
    
         
            +
                      when Symbol
         
     | 
| 
      
 120 
     | 
    
         
            +
                        apply_mapping(source)
         
     | 
| 
      
 121 
     | 
    
         
            +
                      when String, Proc
         
     | 
| 
      
 122 
     | 
    
         
            +
                        source
         
     | 
| 
      
 123 
     | 
    
         
            +
                      else
         
     | 
| 
      
 124 
     | 
    
         
            +
                        raise ArgumentError, "Invalid HTTP feature policy source: #{source.inspect}"
         
     | 
| 
      
 125 
     | 
    
         
            +
                      end
         
     | 
| 
      
 126 
     | 
    
         
            +
                    end
         
     | 
| 
      
 127 
     | 
    
         
            +
                  end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  def apply_mapping(source)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    MAPPINGS.fetch(source) do
         
     | 
| 
      
 131 
     | 
    
         
            +
                      raise ArgumentError, "Unknown HTTP feature policy source mapping: #{source.inspect}"
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                  def build_directives(context)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    @directives.map do |directive, sources|
         
     | 
| 
      
 137 
     | 
    
         
            +
                      if sources.is_a?(Array)
         
     | 
| 
      
 138 
     | 
    
         
            +
                        "#{directive} #{build_directive(sources, context).join(' ')}"
         
     | 
| 
      
 139 
     | 
    
         
            +
                      elsif sources
         
     | 
| 
      
 140 
     | 
    
         
            +
                        directive
         
     | 
| 
      
 141 
     | 
    
         
            +
                      else
         
     | 
| 
      
 142 
     | 
    
         
            +
                        nil
         
     | 
| 
      
 143 
     | 
    
         
            +
                      end
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  def build_directive(sources, context)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    sources.map { |source| resolve_source(source, context) }
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                  def resolve_source(source, context)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    case source
         
     | 
| 
      
 153 
     | 
    
         
            +
                    when String
         
     | 
| 
      
 154 
     | 
    
         
            +
                      source
         
     | 
| 
      
 155 
     | 
    
         
            +
                    when Symbol
         
     | 
| 
      
 156 
     | 
    
         
            +
                      source.to_s
         
     | 
| 
      
 157 
     | 
    
         
            +
                    when Proc
         
     | 
| 
      
 158 
     | 
    
         
            +
                      if context.nil?
         
     | 
| 
      
 159 
     | 
    
         
            +
                        raise RuntimeError, "Missing context for the dynamic feature policy source: #{source.inspect}"
         
     | 
| 
      
 160 
     | 
    
         
            +
                      else
         
     | 
| 
      
 161 
     | 
    
         
            +
                        context.instance_exec(&source)
         
     | 
| 
      
 162 
     | 
    
         
            +
                      end
         
     | 
| 
      
 163 
     | 
    
         
            +
                    else
         
     | 
| 
      
 164 
     | 
    
         
            +
                      raise RuntimeError, "Unexpected feature policy source: #{source.inspect}"
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
              end
         
     | 
| 
      
 168 
     | 
    
         
            +
            end
         
     |