Class: Rack::UTF8Sanitizer

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

Defined Under Namespace

Classes: NullByteInString, SanitizedRackInput

Constant Summary collapse

StringIO =
::StringIO
NULL_BYTE_REGEX =
/\x00/.freeze
DEFAULT_STRATEGIES =
{
  replace: lambda do |input, sanitize_null_bytes: false|
    input.
      force_encoding(Encoding::ASCII_8BIT).
      encode!(Encoding::UTF_8,
              invalid: :replace,
              undef:   :replace)
    if sanitize_null_bytes
      input = input.gsub(NULL_BYTE_REGEX, "")
    end
    input
  end,
  exception: lambda do |input, sanitize_null_bytes: false|
    input.
      force_encoding(Encoding::ASCII_8BIT).
      encode!(Encoding::UTF_8)
    if sanitize_null_bytes && NULL_BYTE_REGEX.match?(input)
      raise NullByteInString
    end
    input
  end
}.freeze
URI_FIELDS =
%w(
    SCRIPT_NAME
    REQUEST_PATH REQUEST_URI PATH_INFO
    QUERY_STRING
    HTTP_REFERER
    ORIGINAL_FULLPATH
    ORIGINAL_SCRIPT_NAME
    SERVER_NAME
).freeze
SANITIZABLE_CONTENT_TYPES =
%w(
  text/plain
  application/x-www-form-urlencoded
  application/json
  text/javascript
).freeze
URI_ENCODED_CONTENT_TYPES =
%w(
  application/x-www-form-urlencoded
).freeze
HTTP_ =
'HTTP_'

Instance Method Summary collapse

Constructor Details

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

options Array options Array



17
18
19
20
21
22
23
24
25
# File 'lib/rack/utf8_sanitizer.rb', line 17

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
  @sanitize_null_bytes = options.fetch(:sanitize_null_bytes, false)
end

Instance Method Details

#call(env) ⇒ Object



27
28
29
30
31
32
33
34
# File 'lib/rack/utf8_sanitizer.rb', line 27

def call(env)
  begin
    env = sanitize(env)
  rescue EOFError
    return [400, { "Content-Type" => "text/plain" }, ["Bad Request"]]
  end
  @app.call(env)
end

#sanitize(env) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rack/utf8_sanitizer.rb', line 83

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