fix #14082, don't crash on incorrectly formatted input (#14977) [backport]

(cherry picked from commit c62513049c)
This commit is contained in:
Miran
2020-07-17 10:59:53 +02:00
committed by narimiran
parent 1b093d7ec7
commit 27acb43e69
3 changed files with 43 additions and 43 deletions

View File

@@ -32,12 +32,7 @@
import strutils, os, strtabs, cookies, uri
export uri.encodeUrl, uri.decodeUrl
proc handleHexChar(c: char, x: var int) {.inline.} =
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: assert(false)
include includes/decode_helpers
proc addXmlChar(dest: var string, c: char) {.inline.} =
case c
@@ -93,40 +88,27 @@ proc getEncodedData(allowedMethods: set[RequestMethod]): string =
iterator decodeData*(data: string): tuple[key, value: TaintedString] =
## Reads and decodes CGI data and yields the (name, value) pairs the
## data consists of.
proc parseData(data: string, i: int, field: var string): int =
result = i
while result < data.len:
case data[result]
of '%': add(field, decodePercent(data, result))
of '+': add(field, ' ')
of '=', '&': break
else: add(field, data[result])
inc(result)
var i = 0
var name = ""
var value = ""
# decode everything in one pass:
while i < data.len:
setLen(name, 0) # reuse memory
while i < data.len:
case data[i]
of '%':
var x = 0
handleHexChar(data[i+1], x)
handleHexChar(data[i+2], x)
inc(i, 2)
add(name, chr(x))
of '+': add(name, ' ')
of '=', '&': break
else: add(name, data[i])
inc(i)
i = parseData(data, i, name)
if i >= data.len or data[i] != '=': cgiError("'=' expected")
inc(i) # skip '='
setLen(value, 0) # reuse memory
while i < data.len:
case data[i]
of '%':
var x = 0
if i+2 < data.len:
handleHexChar(data[i+1], x)
handleHexChar(data[i+2], x)
inc(i, 2)
add(value, chr(x))
of '+': add(value, ' ')
of '&', '\0': break
else: add(value, data[i])
inc(i)
i = parseData(data, i, value)
yield (name.TaintedString, value.TaintedString)
if i < data.len:
if data[i] == '&': inc(i)

View File

@@ -0,0 +1,24 @@
# Include file that implements 'decodePercent' and friends. Do not import it!
proc handleHexChar(c: char, x: var int, f: var bool) {.inline.} =
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: f = true
proc decodePercent(s: string, i: var int): char =
## Converts `%xx` hexadecimal to the charracter with ordinal number `xx`.
##
## If `xx` is not a valid hexadecimal value, it is left intact: only the
## leading `%` is returned as-is, and `xx` characters will be processed in the
## next step (e.g. in `uri.decodeUrl`) as regular characters.
result = '%'
if i+2 < s.len:
var x = 0
var failed = false
handleHexChar(s[i+1], x, failed)
handleHexChar(s[i+2], x, failed)
if not failed:
result = chr(x)
inc(i, 2)

View File

@@ -37,7 +37,9 @@
## else:
## echo "Wrong format"
import strutils, parseutils
import strutils, parseutils, base64
include includes/decode_helpers
type
Url* = distinct string
@@ -81,6 +83,7 @@ proc decodeUrl*(s: string, decodePlus = true): string =
## This means that any ``%xx`` (where ``xx`` denotes a hexadecimal
## value) are converted to the character with ordinal number ``xx``,
## and every other character is carried over.
## If ``xx`` is not a valid hexadecimal value, it is left intact.
##
## As a special rule, when the value of ``decodePlus`` is true, ``+``
## characters are converted to a space.
@@ -92,12 +95,7 @@ proc decodeUrl*(s: string, decodePlus = true): string =
assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test"
assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test",
false) == "https://nim-lang.org/this is a test"
proc handleHexChar(c: char, x: var int) {.inline.} =
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: assert(false)
assert decodeUrl("abc%xyz") == "abc%xyz"
result = newString(s.len)
var i = 0
@@ -105,11 +103,7 @@ proc decodeUrl*(s: string, decodePlus = true): string =
while i < s.len:
case s[i]
of '%':
var x = 0
handleHexChar(s[i+1], x)
handleHexChar(s[i+2], x)
inc(i, 2)
result[j] = chr(x)
result[j] = decodePercent(s, i)
of '+':
if decodePlus:
result[j] = ' '