Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More standard application/x-www-form-urlencoded parsing #5110

Merged
merged 1 commit into from Feb 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -3,6 +3,8 @@
*/
package play.core.parsers

import java.net.URLDecoder

/** An object for parsing application/x-www-form-urlencoded data */
object FormUrlEncodedParser {

Expand Down Expand Up @@ -63,26 +65,20 @@ object FormUrlEncodedParser {
}.asJava
}

private[this] val parameterDelimiter = "[&;]".r

/**
* Do the basic parsing into a sequence of key/value pairs
* @param data The data to parse
* @param encoding The encoding to use for interpreting the data
* @return The sequence of key/value pairs
*/
private def parseToPairs(data: String, encoding: String): Seq[(String, String)] = {

import java.net._

// Generate all the pairs, with potentially redundant key values, by parsing the body content.
data.split('&').flatMap { param =>
if (param.contains("=") && !param.startsWith("=")) {
val parts = param.split("=")
val key = URLDecoder.decode(parts.head, encoding)
val value = URLDecoder.decode(parts.tail.headOption.getOrElse(""), encoding)
Seq(key -> value)
} else {
Nil
}
}.toSeq
parameterDelimiter.split(data).map { param =>
val parts = param.split("=", -1)
val key = URLDecoder.decode(parts(0), encoding)
val value = URLDecoder.decode(parts.lift(1).getOrElse(""), encoding)
key -> value
}
}
}
Expand Up @@ -10,11 +10,24 @@ object FormUrlEncodedParserSpec extends Specification {
"decode forms" in {
FormUrlEncodedParser.parse("foo1=bar1&foo2=bar2") must_== Map("foo1" -> List("bar1"), "foo2" -> List("bar2"))
}
"decode forms with semicolons" in {
// http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2
FormUrlEncodedParser.parse("foo1=bar1;foo2=bar2") must_== Map("foo1" -> List("bar1"), "foo2" -> List("bar2"))
}
"decode forms with ampersands and semicolons" in {
FormUrlEncodedParser.parse("foo1=bar1&foo2=bar2;foo3=bar3") must_== Map("foo1" -> List("bar1"), "foo2" -> List("bar2"), "foo3" -> List("bar3"))
}
"decode form elements with multiple values" in {
FormUrlEncodedParser.parse("foo=bar1&foo=bar2") must_== Map("foo" -> List("bar1", "bar2"))
}
"decode fields with empty names" in {
FormUrlEncodedParser.parse("foo=bar&=") must_== Map("foo" -> List("bar"))
FormUrlEncodedParser.parse("foo=bar&=") must_== Map("foo" -> List("bar"), "" -> List(""))
}
"decode fields with empty values" in {
FormUrlEncodedParser.parse("foo=bar&baz=") must_== Map("foo" -> List("bar"), "baz" -> List(""))
}
"decode fields with no value" in {
FormUrlEncodedParser.parse("foo=bar&baz") must_== Map("foo" -> List("bar"), "baz" -> List(""))
}
"ensure field order is retained, when requested" in {
val url_encoded = "Zero=zero&One=one&Two=two&Three=three&Four=four&Five=five&Six=six&Seven=seven"
Expand Down