Add conditional filtering of param values

This commit is contained in:
Rob Watson 2017-07-14 13:06:17 +01:00
parent 7384706871
commit 8eb23cef04
3 changed files with 82 additions and 0 deletions

View File

@ -45,6 +45,12 @@ Strip a parameter named `client_id` from a fuzzy path:
use Rack::FilterParam, { param: :client_id, path: /\A\/oauth/ }
```
Strip a parameter named `client_id` based on arbitrary logic:
```ruby
use Rack::FilterParam, { param: :client_id, if: -> (value) { ... } }
```
To filter multiple parameters, an array of parameters or options hashes can also be passed.
## Contributing

View File

@ -23,6 +23,8 @@ module Rack
def process_param(param)
return unless path_matches?(param)
return unless param_exists?(param)
return unless affirmative_conditional?(param)
param = param[:param] if param.is_a?(Hash)
@ -43,6 +45,24 @@ module Rack
false
end
def param_exists?(param)
param = param.is_a?(Hash) ? param[:param] : param
params.has_key?(param.to_s)
end
def params
action_dispatch_parsed? ? action_dispatch_params : request.params
end
def affirmative_conditional?(param)
return true unless param.is_a?(Hash)
callable, param = param[:if], param[:param]
return true if callable.nil?
callable.call(params[param.to_s])
end
def delete_from_action_dispatch(param)
action_dispatch_parsed? && !!action_dispatch_params.delete(param.to_s)
end

View File

@ -36,6 +36,18 @@ RSpec.describe Rack::FilterParam do
}
end
shared_context 'middleware with conditional filter' do
let(:app) {
Rack::Builder.new do
use Rack::FilterParam, {
param: :x,
if: ->(value) { value == 'yes' }
}
run -> (env) { [200, {}, ['OK']] }
end.to_app
}
end
shared_examples 'core functionality' do
context 'sending a param that is not expected to be filtered' do
let(:params) { { 'a' => '1' } }
@ -134,6 +146,35 @@ RSpec.describe Rack::FilterParam do
end
end
shared_examples 'conditional filtering' do
context 'when the value should be filtered' do
let(:params) { { 'x' => 'yes', 'y' => 'no' } }
it 'filters the param' do
expect(params_to_test.keys).to eq ['y']
end
it 'includes the param in `rack.filtered_params`' do
expect(last_request.env['rack.filtered_params'])
.to eq [['x', nil]]
end
end
context 'when the value should not be filtered' do
let(:params) { { 'x' => 'no', 'y' => 'no' } }
it 'does not filter the param' do
expect(params_to_test)
.to eq('x' => 'no', 'y' => 'no')
end
it 'does not include the param in `rack.filtered_params`' do
expect(last_request.env['rack.filtered_params'])
.to be nil
end
end
end
context 'GET request' do
let(:method) { :get }
@ -146,6 +187,11 @@ RSpec.describe Rack::FilterParam do
include_context 'middleware with filtered paths'
include_examples 'path filtering'
end
describe 'conditional filtering' do
include_context 'middleware with conditional filter'
include_examples 'conditional filtering'
end
end
context 'POST request' do
@ -166,6 +212,11 @@ RSpec.describe Rack::FilterParam do
include_context 'middleware with filtered paths'
include_examples 'path filtering'
end
describe 'conditional filtering' do
include_context 'middleware with conditional filter'
include_examples 'conditional filtering'
end
end
context 'Request previously parsed by ActionDispatch::ParamsParser' do
@ -186,5 +237,10 @@ RSpec.describe Rack::FilterParam do
include_context 'middleware with filtered paths'
include_examples 'path filtering'
end
describe 'conditional filtering' do
include_context 'middleware with conditional filter'
include_examples 'conditional filtering'
end
end
end