Skip to content

Commit 9a728d2

Browse files
ungitngocdaothanh
authored andcommitted
Response bad request 400 for incorrect param types Char, Boolean, Byte, Short, Int, Long, Float, Double (#681)
1 parent cdec588 commit 9a728d2

File tree

2 files changed

+67
-8
lines changed

2 files changed

+67
-8
lines changed

src/main/scala/xitrum/scope/request/ParamAccess.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import scala.reflect.runtime.universe._
44
import io.netty.handler.codec.http.multipart.FileUpload
55

66
import xitrum.Action
7-
import xitrum.exception.MissingParam
7+
import xitrum.exception.{InvalidInput, MissingParam}
88
import xitrum.util.DefaultsTo
99

1010
/**
@@ -43,7 +43,7 @@ trait ParamAccess {
4343
} else {
4444
coll.get(key) match {
4545
case None => throw new MissingParam(key)
46-
case Some(values) => convertTextParam[T](values.head)
46+
case Some(values) => convertTextParam[T](key, values.head)
4747
}
4848
}
4949
}
@@ -55,7 +55,7 @@ trait ParamAccess {
5555
if (typeOf[T] <:< TYPE_FILE_UPLOAD) {
5656
bodyFileParams.get(key).map(_.head.asInstanceOf[T])
5757
} else {
58-
coll.get(key).map(values => convertTextParam[T](values.head))
58+
coll.get(key).map(values => convertTextParam[T](key, values.head))
5959
}
6060
}
6161

@@ -71,17 +71,17 @@ trait ParamAccess {
7171
} else {
7272
coll.get(key) match {
7373
case None => Seq.empty
74-
case Some(values) => values.map(convertTextParam[T])
74+
case Some(values) => values.map(convertTextParam[T](key, _))
7575
}
7676
}
7777
}
7878

7979
//----------------------------------------------------------------------------
8080

8181
/** Applications may override this method to convert to more types. */
82-
def convertTextParam[T: TypeTag](value: String): T = {
82+
def convertTextParam[T: TypeTag](key: String, value: String): T = {
8383
val t = typeOf[T]
84-
val any: Any =
84+
scala.util.Try[Any] {
8585
if (t <:< TYPE_STRING) value
8686
else if (t <:< TYPE_CHAR) value(0)
8787
else if (t <:< TYPE_BOOLEAN) value.toBoolean
@@ -91,7 +91,11 @@ trait ParamAccess {
9191
else if (t <:< TYPE_LONG) value.toLong
9292
else if (t <:< TYPE_FLOAT) value.toFloat
9393
else if (t <:< TYPE_DOUBLE) value.toDouble
94-
else throw new Exception("convertTextParam cannot covert " + value + " to " + t)
95-
any.asInstanceOf[T]
94+
else throw new Exception(s"convertTextParam $key cannot convert $value to $t")
95+
}.recoverWith {
96+
case _: StringIndexOutOfBoundsException |
97+
_: IllegalArgumentException =>
98+
scala.util.Failure(new InvalidInput(s"""Cannot convert "$value" of param "$key" to $t"""))
99+
}.get.asInstanceOf[T]
96100
}
97101
}

src/test/scala/xitrum/params/ParamsTest.scala

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ class ParamsPayloadTestAction extends Action with SkipCsrfCheck {
4848
}
4949
}
5050

51+
@GET("test/params/validation")
52+
class ParamsValidationTestAction extends Action with SkipCsrfCheck {
53+
def execute() {
54+
param[Char]("keyChar")
55+
param[Int]("keyInt")
56+
param[Boolean]("keyBoolean")
57+
58+
respondText("Ok")
59+
}
60+
}
61+
5162
class ParamsTest extends FlatSpec with Matchers with BeforeAndAfter with Log {
5263
private implicit val formats = Serialization.formats(NoTypeHints)
5364
private val base = "http://127.0.0.1:8000/my_site"
@@ -107,6 +118,50 @@ class ParamsTest extends FlatSpec with Matchers with BeforeAndAfter with Log {
107118
shouldEqual(response, ParamsPayloadResponse(1, Seq(2, 3), "ru-RU", Some("value")))
108119
}
109120

121+
"[GET] param" should "response validation error char" in {
122+
val response = client.prepareGet(s"$base/test/params/validation")
123+
.addQueryParam("keyChar", "")
124+
.addQueryParam("keyInt", "1")
125+
.addQueryParam("keyBoolean", "true")
126+
.execute().get()
127+
(response.getStatusCode, response.getResponseBody) shouldEqual
128+
(400, """Validation error: Cannot convert "" of param "keyChar" to Char""")
129+
}
130+
131+
"[GET] param" should "response validation error overflow int" in {
132+
val keyValue = Int.MaxValue + 1L
133+
val response = client.prepareGet(s"$base/test/params/validation")
134+
.addQueryParam("keyChar", "a")
135+
.addQueryParam("keyInt", keyValue.toString)
136+
.addQueryParam("keyBoolean", "true")
137+
.execute().get()
138+
(response.getStatusCode, response.getResponseBody) shouldEqual
139+
(400, s"""Validation error: Cannot convert "$keyValue" of param "keyInt" to Int""")
140+
}
141+
142+
143+
"[GET] param" should "response validation error parse int" in {
144+
val keyValue = "1a"
145+
val response = client.prepareGet(s"$base/test/params/validation")
146+
.addQueryParam("keyChar", "a")
147+
.addQueryParam("keyInt", keyValue)
148+
.addQueryParam("keyBoolean", "true")
149+
.execute().get()
150+
(response.getStatusCode, response.getResponseBody) shouldEqual
151+
(400, s"""Validation error: Cannot convert "$keyValue" of param "keyInt" to Int""")
152+
}
153+
154+
"[GET] param" should "response validation error parse boolean" in {
155+
val value = "tru"
156+
val response = client.prepareGet(s"$base/test/params/validation")
157+
.addQueryParam("keyChar", "c")
158+
.addQueryParam("keyInt", "1")
159+
.addQueryParam("keyBoolean", value)
160+
.execute().get()
161+
(response.getStatusCode, response.getResponseBody) shouldEqual
162+
(400, s"""Validation error: Cannot convert "$value" of param "keyBoolean" to Boolean""")
163+
}
164+
110165
private def shouldEqual[T](response: Response, expected: T)(implicit formats: Formats, mf: Manifest[T]) = {
111166
if (response.getStatusCode != 200) {
112167
log.warn(s"Response:\n$response")

0 commit comments

Comments
 (0)