implement escaped params

This commit is contained in:
Konstantin Haase 2011-05-25 11:49:39 +02:00
parent 5535bf89f5
commit 2f2a95da69
2 changed files with 76 additions and 2 deletions

View File

@ -1,4 +1,5 @@
require 'rack/protection'
require 'escape_utils'
module Rack
module Protection
@ -9,10 +10,54 @@ module Rack
#
# Automatically escapes Rack::Request#params so they can be embedded in HTML
# or JavaScript without any further issues. Calls +html_safe+ on the escaped
# strings if defined, to avoid double-escaping in Rails.
# strings if defined, to avoid double-escaping in Rails. It does only escape
# for embedding in HTML and Javascript by default, so you have to take care
# of URLs or SQL injection yourself.
#
# Not Yet Implemented!
# Options:
# escape:: What escaping modes to use, should be Symbol or Array of Symbols.
# Available: :html, :javascript, :url, default: [:html, :javascript]
class EscapedParams < Base
default_options :escape => [:html, :javascript]
def initialize(*)
super
modes = Array options[:escape]
code = "def self.escape_string(str) %s end"
modes.each { |m| code %= "EscapeUtils.escape_#{m}(%s)"}
eval code % 'str'
end
def call(env)
request = Request.new(env)
get_was = handle(request.GET)
post_was = handle(request.POST) rescue nil
app.call env
ensure
request.GET.replace get_was
request.POST.replace post_was if post_was
end
def handle(hash)
was = hash.dup
hash.replace escape(hash)
was
end
def escape(object)
case object
when Hash then escape_hash(object)
when Array then object.map { |o| escape(o) }
when String then escape_string(object)
else raise ArgumentError, "cannot escape #{object.inspect}"
end
end
def escape_hash(hash)
hash = hash.dup
hash.each { |k,v| hash[k] = escape(v) }
hash
end
end
end
end

View File

@ -2,4 +2,33 @@ require File.expand_path('../spec_helper.rb', __FILE__)
describe Rack::Protection::EscapedParams do
it_behaves_like "any rack application"
context 'escaping' do
it 'escapes html entities' do
mock_app do |env|
request = Rack::Request.new(env)
[200, {'Content-Type' => 'text/plain'}, [request.params['foo']]]
end
get '/', :foo => "<bar>"
body.should == '&lt;bar&gt;'
end
it 'leaves normal params untouched' do
mock_app do |env|
request = Rack::Request.new(env)
[200, {'Content-Type' => 'text/plain'}, [request.params['foo']]]
end
get '/', :foo => "bar"
body.should == 'bar'
end
it 'copes with nested arrays' do
mock_app do |env|
request = Rack::Request.new(env)
[200, {'Content-Type' => 'text/plain'}, [request.params['foo']['bar']]]
end
get '/', :foo => {:bar => "<bar>"}
body.should == '&lt;bar&gt;'
end
end
end