Module: Datadog::AppSec::RouteNormalizer::RouteText Private

Defined in:
lib/datadog/appsec/route_normalizer/route_text.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Percent-encodes route text, leaving param templates untouched

Constant Summary collapse

DISALLOWED_CHARS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%r{[^\w.~/-]}
BYTE_ENCODING_TABLE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Per-byte percent-encoding lookup, indexed by byte value (0-255)

Example:

32 => 20   (space)
33 => 21   (!)
47 => /     (passthrough)
65 => A     (passthrough)

195 => %C3 (UTF-8 lead byte) 169 => %A9 (UTF-8 continuation byte)

Array.new(256) do |byte|
  char = byte.chr
  char.match?(DISALLOWED_CHARS) ? -("%%%02X" % byte) : -char
end.freeze
MAX_ENCODED_BYTE_SIZE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Max bytes one input byte expands to as percent-encoded %XX

3

Class Method Summary collapse

Class Method Details

.escape(text) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Escapes literal route text into normalized-route form

Example:

a+b => a%2Bb
caf

NOTE: URI::Parser#escape with DISALLOWED_CHARS gives the same output, but the generic gsub/sprintf path is slower and allocates more per request



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/datadog/appsec/route_normalizer/route_text.rb', line 42

def escape(text)
  return text unless text.match?(DISALLOWED_CHARS)

  buffer = String.new(capacity: text.bytesize * MAX_ENCODED_BYTE_SIZE, encoding: Encoding::UTF_8)
  text.each_byte { |byte| buffer << BYTE_ENCODING_TABLE.fetch(byte) }
  buffer
# NOTE: Defensive only — this can never happen. {String#each_byte} yields
#       integers in 0-255 and {BYTE_ENCODING_TABLE} has an entry for every one
rescue IndexError => e
  AppSec.telemetry&.report(e, description: "AppSec: Route text byte outside 0-255 escape table")
  "~invalid~"
end