diff options
-rw-r--r-- | changelog.md | 10 | ||||
-rw-r--r-- | lib/pure/cgi.nim | 14 | ||||
-rw-r--r-- | lib/pure/uri.nim | 38 | ||||
-rw-r--r-- | tests/stdlib/turi.nim | 3 |
4 files changed, 38 insertions, 27 deletions
diff --git a/changelog.md b/changelog.md index 285977488..8bdbc7416 100644 --- a/changelog.md +++ b/changelog.md @@ -96,6 +96,16 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior. - Added `socketstream` module that wraps sockets in the stream interface +- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` + characters in the decoded values. Prior versions would raise an error. This is + no longer the case to comply with the HTML spec and other languages + implementations. Old behavior can be obtained with + `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same + underlying code is also updated the same way. + + + + - Added `math.signbit`. - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably) diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index 8d827f555..3b8dad849 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -84,11 +84,8 @@ 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. - try: - for (key, value) in uri.decodeQuery(data): - yield (key, value) - except UriParseError as e: - cgiError(e.msg) + for (key, value) in uri.decodeQuery(data): + yield (key, value) iterator decodeData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = @@ -96,11 +93,8 @@ iterator decodeData*(allowedMethods: set[RequestMethod] = ## data consists of. If the client does not use a method listed in the ## `allowedMethods` set, a `CgiError` exception is raised. let data = getEncodedData(allowedMethods) - try: - for (key, value) in uri.decodeQuery(data): - yield (key, value) - except UriParseError as e: - cgiError(e.msg) + for (key, value) in uri.decodeQuery(data): + yield (key, value) proc readData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): StringTableRef = diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 7f553be1a..c8ed28536 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -161,22 +161,26 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true, result.add(encodeUrl(val, usePlus)) iterator decodeQuery*(data: string): tuple[key, value: TaintedString] = - ## Reads and decodes query string ``data`` and yields the (key, value) pairs the - ## data consists of. + ## Reads and decodes query string `data` and yields the `(key, value)` pairs + ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, an + ## error is raised when there is an unencoded `=` character in a decoded + ## value, which was the behavior in Nim < 1.5.1 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")] + import std/sequtils + doAssert toSeq(decodeQuery("foo=1&bar=2=3")) == @[("foo", "1"), ("bar", "2=3")] + doAssert toSeq(decodeQuery("&a&=b&=&&")) == @[("", ""), ("a", ""), ("", "b"), ("", ""), ("", "")] - 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 @@ -185,16 +189,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 diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index 6354850fc..1abab7a19 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -287,8 +287,7 @@ template main() = block: # decodeQuery doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")] - doAssertRaises(UriParseError): - discard toSeq(decodeQuery("a=1&b=2c=6")) + doAssert toSeq(decodeQuery("a=1&b=2c=6")) == @[("a", "1"), ("b", "2c=6")] static: main() main() |