Skip to content

Commit

Permalink
Improve uri.parseQuery to never raise an error
Browse files Browse the repository at this point in the history
In case of malformed query string where there is `=` on the value, handle
this character as part of the value instead of throwing an error.

The following query string should no longer crash a program:

    key=value&key2=x=1

It will be interpreted as [("key", "value"), ("key2", "x=1")]

This is correct according to latest WhatWG's HTML5 specification
recarding the urlencoded parser:
https://url.spec.whatwg.org/#concept-urlencoded-parser

Older behavior can be restored using the -d:nimLegacyParseQueryStrict
flag.
  • Loading branch information
mildred committed Jan 11, 2021
1 parent fd5c8ef commit a296b4f
Showing 1 changed file with 19 additions and 12 deletions.
31 changes: 19 additions & 12 deletions lib/pure/uri.nim
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,21 @@ iterator decodeQuery*(data: string): tuple[key, value: TaintedString] =
## data consists of.
runnableExamples:
import std/sugar
let s = collect(newSeq):
for k, v in decodeQuery("foo=1&bar=2"): (k, v)
doAssert s == @[("foo", "1"), ("bar", "2")]
let s = collect:
for k, v in decodeQuery("foo=1&bar=2=3"): (k, v)
doAssert s == @[("foo", "1"), ("bar", "2=3")]

proc parseData(data: string, i: int, field: var string): int =
proc parseData(data: string, i: int, field: var string, sep: char): int =
result = i
while result < data.len:
case data[result]
let c = data[result]
case c
of '%': add(field, decodePercent(data, result))
of '+': add(field, ' ')
of '=', '&': break
else: add(field, data[result])
of '&': break
else:
if c == sep: break
else: add(field, data[result])
inc(result)

var i = 0
Expand All @@ -185,16 +188,20 @@ iterator decodeQuery*(data: string): tuple[key, value: TaintedString] =
# decode everything in one pass:
while i < data.len:
setLen(name, 0) # reuse memory
i = parseData(data, i, name)
i = parseData(data, i, name, '=')
setLen(value, 0) # reuse memory
if i < data.len and data[i] == '=':
inc(i) # skip '='
i = parseData(data, i, value)
when defined(nimLegacyParseQueryStrict):
i = parseData(data, i, value, '=')
else:
i = parseData(data, i, value, '&')
yield (name.TaintedString, value.TaintedString)
if i < data.len:
if data[i] == '&': inc(i)
else:
uriParseError("'&' expected at index '$#' for '$#'" % [$i, data])
when defined(nimLegacyParseQueryStrict):
if data[i] != '&':
uriParseError("'&' expected at index '$#' for '$#'" % [$i, data])
inc(i)

func parseAuthority(authority: string, result: var Uri) =
var i = 0
Expand Down

0 comments on commit a296b4f

Please sign in to comment.