Class: Rack::UTF8Sanitizer

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/utf8_sanitizer.rb

Defined Under Namespace

Classes: SanitizedRackInput

Constant Summary collapse

StringIO =
::StringIO
BAD_REQUEST =
[400, { "Content-Type" => "text/plain" }, ["Bad Request"]]
DEFAULT_STRATEGIES =
{
  replace: lambda do |input|
    input.
      force_encoding(Encoding::ASCII_8BIT).
      encode!(Encoding::UTF_8,
              invalid: :replace,
              undef:   :replace)
  end,
  exception: lambda do |input|
    input.
      force_encoding(Encoding::ASCII_8BIT).
      encode!(Encoding::UTF_8)
  end
}.freeze
URI_FIELDS =
%w(
    SCRIPT_NAME
    REQUEST_PATH REQUEST_URI PATH_INFO
    QUERY_STRING
    HTTP_REFERER
    ORIGINAL_FULLPATH
    ORIGINAL_SCRIPT_NAME
    SERVER_NAME
).map(&:freeze).freeze
SANITIZABLE_CONTENT_TYPES =
%w(
  text/plain
  application/x-www-form-urlencoded
  application/json
  text/javascript
).map(&:freeze).freeze
URI_ENCODED_CONTENT_TYPES =
%w(
  application/x-www-form-urlencoded
).map(&:freeze).freeze
HTTP_ =
'HTTP_'.freeze

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ UTF8Sanitizer

options Array options Array



13
14
15
16
17
18
19
20
# File 'lib/rack/utf8_sanitizer.rb', line 13

def initialize(app, options={})
  @app = app
  @strategy = build_strategy(options)
  @sanitizable_content_types = options[:sanitizable_content_types]
  @sanitizable_content_types ||= SANITIZABLE_CONTENT_TYPES + (options[:additional_content_types] || [])
  @only = Array(options[:only]).flatten
  @except = Array(options[:except]).flatten
end

Instance Method Details

#call(env) ⇒ Object



22
23
24
25
26
27
28
29
# File 'lib/rack/utf8_sanitizer.rb', line 22

def call(env)
  begin
    env = sanitize(env)
  rescue EOFError
    return BAD_REQUEST
  end
  @app.call(env)
end

#sanitize(env) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rack/utf8_sanitizer.rb', line 70

def sanitize(env)
  sanitize_rack_input(env)
  sanitize_cookies(env)
  env.each do |key, value|
    next if skip?(key)

    if URI_FIELDS.include?(key)
      env[key] = transfer_frozen(value,
          sanitize_uri_encoded_string(value))
    elsif key.to_s.start_with?(HTTP_)
      # Just sanitize the headers and leave them in UTF-8. There is
      # no reason to have UTF-8 in headers, but if it's valid, let it be.
      env[key] = transfer_frozen(value,
          sanitize_string(value))
    end
  end
end