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

Commit

Permalink
! http: introduce a distinction between "?key=" and "?key" in queries,
Browse files Browse the repository at this point in the history
…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`.
  • Loading branch information
jrudolph committed Sep 26, 2013
1 parent 80e59e1 commit d2b8bba
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 6 deletions.
6 changes: 5 additions & 1 deletion spray-http/src/main/scala/spray/http/Uri.scala
Expand Up @@ -438,7 +438,8 @@ object Uri {
case Query.Cons(key, value, tail)
if (q ne this) r ~~ '&'
enc(key)
if (!value.isEmpty) { r ~~ '='; enc(value) }
if (value ne Query.EmptyValue) r ~~ '='
enc(value)
append(tail)
case Query.Raw(value) r ~~ value
}
Expand All @@ -447,6 +448,9 @@ object Uri {
override def newBuilder: mutable.Builder[(String, String), Query] = Query.newBuilder
}
object Query {
/** A special empty String value which will be rendered without a '=' after the key. */
val EmptyValue: String = new String(Array.empty[Char])

/**
* Parses the given String into a Query instance.
* Note that this method will never return Query.Empty, even for the empty String.
Expand Down
Expand Up @@ -302,7 +302,7 @@ private[http] class UriParser(input: ParserInput, charset: Charset, mode: Uri.Pa
// putting some pressure onto the JVM stack
def readKVP(): Query = {
val key = part
val value = if (ch('=')) part else ""
val value = if (ch('=')) part else Query.EmptyValue
val tail = if (ch('&')) readKVP() else Query.Empty
Query.Cons(key, value, tail)
}
Expand Down
4 changes: 2 additions & 2 deletions spray-http/src/test/scala/spray/http/UriSpec.scala
Expand Up @@ -361,8 +361,8 @@ class UriSpec extends Specification {
// queries
normalize("?") === "?"
normalize("?key") === "?key"
normalize("?key=") === "?key" // our query model cannot discriminate between these two inputs
normalize("?key=&a=b") === "?key&a=b" // our query model cannot discriminate between these two inputs
normalize("?key=") === "?key="
normalize("?key=&a=b") === "?key=&a=b"
normalize("?key={}&a=[]") === "?key=%7B%7D&a=%5B%5D"
normalize("?key={}&a=[]", mode = Uri.ParsingMode.Strict) must throwAn[IllegalUriException]
normalize("?=value") === "?=value"
Expand Down
Expand Up @@ -45,8 +45,8 @@ class BasicMarshallersSpec extends Specification {
"The FormDataMarshaller" should {
"properly marshal FormData instances to application/x-www-form-urlencoded entity bodies" in {
marshal(FormData(Map("name" -> "Bob", "pass" -> "hällo", "admin" -> ""))) ===
Right(HttpEntity(ContentType(`application/x-www-form-urlencoded`, `UTF-8`), "name=Bob&pass=h%E4llo&admin"))
Right(HttpEntity(ContentType(`application/x-www-form-urlencoded`, `UTF-8`), "name=Bob&pass=h%E4llo&admin="))
}
}

}
}

0 comments on commit d2b8bba

Please sign in to comment.