Module: Datadog::AppSec::Utils::HTTP::URLEncoded
- Defined in:
- lib/datadog/appsec/utils/http/url_encoded.rb
Overview
Module for parsing URL encoded payloads
Constant Summary collapse
- DEFAULT_BYTESIZE_LIMIT =
Matches Rack's default query bytesize limit, so parsing our own payloads keeps the same guard against CPU/memory exhaustion.
4 * 1024 * 1024
- AMPERSAND_BYTE =
0x26- EQUALS_BYTE =
0x3D
Class Method Summary collapse
-
.parse(payload, limit: DEFAULT_BYTESIZE_LIMIT) ⇒ Object
Parses a URL encoded payload (query string or form data) into a hash of keys and values, merging duplicate keys.
Class Method Details
.parse(payload, limit: DEFAULT_BYTESIZE_LIMIT) ⇒ Object
Parses a URL encoded payload (query string or form data) into a hash of keys and values, merging duplicate keys.
Example:
URLEncoded.parse("foo=bar&foo=baz&qux=quux") # => {"foo" => ["bar", "baz"], "qux" => "quux"}
Parsing stops once limit bytes have been read, and the pair being
read at that point is discarded. This returns the pairs decoded so
far rather than raising or discarding the whole payload.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/datadog/appsec/utils/http/url_encoded.rb', line 30 def parse(payload, limit: DEFAULT_BYTESIZE_LIMIT) raise ArgumentError, "limit must not be negative" if limit < 0 return {} if payload.nil? || payload.empty? || limit.zero? # @type var result: URLEncoded::params result = {} payload_bytesize = payload.bytesize bytes_to_parse = (payload_bytesize < limit) ? payload_bytesize : limit index = 0 param_start = 0 equals_index = nil # : Integer? payload.each_byte do |byte| break if index >= bytes_to_parse if byte == AMPERSAND_BYTE param_end = index if equals_index key = payload.byteslice(param_start, equals_index - param_start) # : String value = payload.byteslice(equals_index + 1, param_end - equals_index - 1) # : String? else key = payload.byteslice(param_start, param_end - param_start) # : String value = nil end if !key.empty? || value key = CGI.unescape(key) value = CGI.unescape(value) if value add_param(result, key, value) end param_start = index + 1 equals_index = nil elsif byte == EQUALS_BYTE equals_index ||= index end index += 1 end if bytes_to_parse == payload_bytesize && param_start < index param_end = index if equals_index key = payload.byteslice(param_start, equals_index - param_start) # : String value = payload.byteslice(equals_index + 1, param_end - equals_index - 1) # : String? else key = payload.byteslice(param_start, param_end - param_start) # : String value = nil end if !key.empty? || value key = CGI.unescape(key) value = CGI.unescape(value) if value add_param(result, key, value) end end result end |