Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default to & as separator instead of either & or ; #1733

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. For info on

## [3.0.0] - Unreleased

### Security

- Do not use semicolon as GET parameter separator. ([#1733](https://github.com/rack/rack/pull/1733), [@jeremyevans](https://github.com/jeremyevans))

### Added

- `Rack::RewindableInput` supports size. ([@ahorek](https://github.com/ahorek))
Expand Down
17 changes: 8 additions & 9 deletions lib/rack/query_parser.rb
Expand Up @@ -4,7 +4,7 @@ module Rack
class QueryParser
(require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'

DEFAULT_SEP = /[&;] */n
DEFAULT_SEP = /[&] */n
COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }

# ParameterTypeError is the error that is raised when incoming structural
Expand All @@ -29,16 +29,15 @@ def initialize(params_class, key_space_limit, param_depth_limit)
end

# Stolen from Mongrel, with some small modifications:
# Parses a query string by breaking it up at the '&'
# and ';' characters. You can also use this to parse
# cookies by changing the characters used in the second
# parameter (which defaults to '&;').
def parse_query(qs, d = nil, &unescaper)
# Parses a query string by breaking it up at the '&'. You can also use this
# to parse cookies by changing the characters used in the second parameter
# (which defaults to '&').
def parse_query(qs, separator = nil, &unescaper)
unescaper ||= method(:unescape)

params = make_params

(qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
(qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
next if p.empty?
k, v = p.split('=', 2).map!(&unescaper)

Expand All @@ -61,11 +60,11 @@ def parse_query(qs, d = nil, &unescaper)
# query strings with parameters of conflicting types, in this case a
# ParameterTypeError is raised. Users are encouraged to return a 400 in this
# case.
def parse_nested_query(qs, d = nil)
def parse_nested_query(qs, separator = nil)
params = make_params

unless qs.nil? || qs.empty?
(qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
(qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
k, v = p.split('=', 2).map! { |s| unescape(s) }

normalize_params(params, k, v, param_depth_limit)
Expand Down
2 changes: 1 addition & 1 deletion lib/rack/request.rb
Expand Up @@ -427,7 +427,7 @@ def GET
if get_header(RACK_REQUEST_QUERY_STRING) == query_string
get_header(RACK_REQUEST_QUERY_HASH)
else
query_hash = parse_query(query_string, '&;')
query_hash = parse_query(query_string, '&')
set_header(RACK_REQUEST_QUERY_STRING, query_string)
set_header(RACK_REQUEST_QUERY_HASH, query_hash)
end
Expand Down
6 changes: 3 additions & 3 deletions test/spec_request.rb
Expand Up @@ -308,12 +308,12 @@ def initialize(*)
req.params[:quux].must_equal "bla"
end

it "use semi-colons as separators for query strings in GET" do
it "does not use semi-colons as separators for query strings in GET" do
req = make_request(Rack::MockRequest.env_for("/?foo=bar&quux=b;la;wun=duh"))
req.query_string.must_equal "foo=bar&quux=b;la;wun=duh"
req.GET.must_equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh"
req.GET.must_equal "foo" => "bar", "quux" => "b;la;wun=duh"
req.POST.must_be :empty?
req.params.must_equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh"
req.params.must_equal "foo" => "bar", "quux" => "b;la;wun=duh"
end

it "limit the keys from the GET query string" do
Expand Down