diff --git a/lib/datadog/appsec/contrib/rack/gateway/request.rb b/lib/datadog/appsec/contrib/rack/gateway/request.rb index b204894a537..86513a697a2 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/request.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/request.rb @@ -25,11 +25,13 @@ def request def query # Downstream libddwaf expects keys and values to be extractable # separately so we can't use [[k, v], ...]. We also want to allow - # duplicate keys, so we use [{k, v}, ...] instead. - request.query_string.split('&').map do |e| + # duplicate keys, so we use {k => [v, ...], ...} instead, taking into + # account that {k => [v1, v2, ...], ...} is possible for duplicate keys. + request.query_string.split('&').each.with_object({}) do |e, hash| k, v = e.split('=').map { |s| CGI.unescape(s) } + hash[k] ||= [] - { k => v } + hash[k] << v end end diff --git a/spec/datadog/appsec/contrib/rack/gateway/request_spec.rb b/spec/datadog/appsec/contrib/rack/gateway/request_spec.rb index 9ee4d422525..495ef2fbb0b 100644 --- a/spec/datadog/appsec/contrib/rack/gateway/request_spec.rb +++ b/spec/datadog/appsec/contrib/rack/gateway/request_spec.rb @@ -8,7 +8,7 @@ let(:request) do described_class.new( Rack::MockRequest.env_for( - 'http://example.com:8080/?a=foo', + 'http://example.com:8080/?a=foo&a=bar&b=baz', { 'REQUEST_METHOD' => 'GET', 'REMOTE_ADDR' => '10.10.10.10', 'HTTP_CONTENT_TYPE' => 'text/html', 'HTTP_COOKIE' => 'foo=bar', 'HTTP_USER_AGENT' => 'WebKit' @@ -19,7 +19,7 @@ describe '#query' do it 'returns URL query information' do - expect(request.query).to eq([{ 'a' => 'foo' }]) + expect(request.query).to eq({ 'a' => ['foo', 'bar'], 'b' => ['baz'] }) end end @@ -38,7 +38,7 @@ describe '#url' do it 'returns the url' do - expect(request.url).to eq('http://example.com:8080/?a=foo') + expect(request.url).to eq('http://example.com:8080/?a=foo&a=bar&b=baz') end end @@ -50,7 +50,7 @@ describe '#fullpath' do it 'returns the path with query string' do - expect(request.fullpath).to eq('/?a=foo') + expect(request.fullpath).to eq('/?a=foo&a=bar&b=baz') end end diff --git a/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb b/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb index 507a585c077..c30f9e4301a 100644 --- a/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb +++ b/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb @@ -20,7 +20,7 @@ describe '.publish' do it 'propagates request attributes to the operation' do expect(operation).to receive(:publish).with('server.request.method', 'GET') - expect(operation).to receive(:publish).with('request.query', [{ 'a' => 'foo' }]) + expect(operation).to receive(:publish).with('request.query', { 'a' => ['foo'] }) expect(operation).to receive(:publish).with('request.headers', { 'content-type' => 'text/html' }) expect(operation).to receive(:publish).with('request.uri.raw', '/?a=foo') expect(operation).to receive(:publish).with('request.cookies', {}) @@ -53,7 +53,7 @@ expected_waf_arguments = { 'server.request.cookies' => {}, - 'server.request.query' => [{ 'a' => 'foo' }], + 'server.request.query' => { 'a' => ['foo'] }, 'server.request.uri.raw' => '/?a=foo', 'server.request.headers' => { 'content-type' => 'text/html' }, 'server.request.headers.no_cookies' => { 'content-type' => 'text/html' },