Skip to content
This repository was archived by the owner on Apr 24, 2024. It is now read-only.

Commit d2b8bba

Browse files
committed
! http: introduce a distinction between "?key=" and "?key" in queries, fixes #460
The breaking change is that a parse/render round-trip will reproduce a trailing '=' if the value is empty as well as no trailing '=' if it was originally missing. Also, the default behavior was changed so that '=' is always rendered even for empty values unless you use the special value `Query.EmptyValue`.
1 parent 80e59e1 commit d2b8bba

File tree

4 files changed

+10
-6
lines changed

4 files changed

+10
-6
lines changed

spray-http/src/main/scala/spray/http/Uri.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,8 @@ object Uri {
438438
case Query.Cons(key, value, tail)
439439
if (q ne this) r ~~ '&'
440440
enc(key)
441-
if (!value.isEmpty) { r ~~ '='; enc(value) }
441+
if (value ne Query.EmptyValue) r ~~ '='
442+
enc(value)
442443
append(tail)
443444
case Query.Raw(value) r ~~ value
444445
}
@@ -447,6 +448,9 @@ object Uri {
447448
override def newBuilder: mutable.Builder[(String, String), Query] = Query.newBuilder
448449
}
449450
object Query {
451+
/** A special empty String value which will be rendered without a '=' after the key. */
452+
val EmptyValue: String = new String(Array.empty[Char])
453+
450454
/**
451455
* Parses the given String into a Query instance.
452456
* Note that this method will never return Query.Empty, even for the empty String.

spray-http/src/main/scala/spray/http/parser/UriParser.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ private[http] class UriParser(input: ParserInput, charset: Charset, mode: Uri.Pa
302302
// putting some pressure onto the JVM stack
303303
def readKVP(): Query = {
304304
val key = part
305-
val value = if (ch('=')) part else ""
305+
val value = if (ch('=')) part else Query.EmptyValue
306306
val tail = if (ch('&')) readKVP() else Query.Empty
307307
Query.Cons(key, value, tail)
308308
}

spray-http/src/test/scala/spray/http/UriSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,8 @@ class UriSpec extends Specification {
361361
// queries
362362
normalize("?") === "?"
363363
normalize("?key") === "?key"
364-
normalize("?key=") === "?key" // our query model cannot discriminate between these two inputs
365-
normalize("?key=&a=b") === "?key&a=b" // our query model cannot discriminate between these two inputs
364+
normalize("?key=") === "?key="
365+
normalize("?key=&a=b") === "?key=&a=b"
366366
normalize("?key={}&a=[]") === "?key=%7B%7D&a=%5B%5D"
367367
normalize("?key={}&a=[]", mode = Uri.ParsingMode.Strict) must throwAn[IllegalUriException]
368368
normalize("?=value") === "?=value"

spray-httpx/src/test/scala/spray/httpx/marshalling/BasicMarshallersSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class BasicMarshallersSpec extends Specification {
4545
"The FormDataMarshaller" should {
4646
"properly marshal FormData instances to application/x-www-form-urlencoded entity bodies" in {
4747
marshal(FormData(Map("name" -> "Bob", "pass" -> "hällo", "admin" -> ""))) ===
48-
Right(HttpEntity(ContentType(`application/x-www-form-urlencoded`, `UTF-8`), "name=Bob&pass=h%E4llo&admin"))
48+
Right(HttpEntity(ContentType(`application/x-www-form-urlencoded`, `UTF-8`), "name=Bob&pass=h%E4llo&admin="))
4949
}
5050
}
5151

52-
}
52+
}

0 commit comments

Comments
 (0)