Permalink
Browse files

! http(x): create FormFile as an easy way to access uploaded file inf…

…ormation for forms, fixes #327
  • Loading branch information...
jrudolph committed Oct 11, 2013
1 parent 3db357e commit ae17d1856d68f27fc4fe9dcc6e876f25cc776736
@@ -51,3 +51,5 @@ object MultipartFormData {
case (key, value) value.copy(headers = `Content-Disposition`("form-data", Map("name" -> key)) +: value.headers)
}.toSeq)
}
case class FormFile(name: Option[String], entity: HttpEntity.NonEmpty)
@@ -125,6 +125,14 @@ trait FormDataUnmarshallers {
}
}
implicit def formFileUnmarshaller: FromBodyPartOptionUnmarshaller[FormFile] =
new FromBodyPartOptionUnmarshaller[FormFile] {
def apply(partOption: Option[BodyPart]): Deserialized[FormFile] = partOption match {
case Some(part @ BodyPart(entity: HttpEntity.NonEmpty, _)) ⇒ Right(FormFile(part.filename, entity))
case _ ⇒ Left(ContentExpected)
}
}
implicit def liftFromEntityOptionUnmarshaller[T](implicit feou: FromEntityOptionUnmarshaller[T]): FromBodyPartOptionUnmarshaller[T] =
new FromBodyPartOptionUnmarshaller[T] {
def apply(part: Option[BodyPart]): Deserialized[T] = feou(part.map(_.entity))
@@ -28,7 +28,9 @@ class FormFieldSpec extends Specification {
val formData =
FormData(Map("surname" -> "Smith", "age" -> "42"))
val multipartFormData =
MultipartFormData(Map("surname" -> BodyPart("Smith"), "age" -> BodyPart(marshal(<int>42</int>).get)))
MultipartFormData(Seq(
BodyPart("Smith", Seq(HttpHeaders.`Content-Disposition`("form-data", Map("name" -> "surname")))),
BodyPart(marshal(<int>42</int>).get, Seq(HttpHeaders.`Content-Disposition`("form-data", Map("filename" -> "age.xml", "name" -> "age"))))))
"The FormField infrastructure" should {
"properly allow access to the fields of www-urlencoded forms" in {
@@ -20,8 +20,6 @@ import shapeless.HNil
import spray.httpx.marshalling.marshalUnsafe
import spray.httpx.unmarshalling.FromStringDeserializers.HexInt
import spray.http._
import scala.xml.NodeSeq
import spray.routing.directives.FieldDefMagnet
class FormFieldDirectivesSpec extends RoutingSpec {
@@ -40,6 +38,8 @@ class FormFieldDirectivesSpec extends RoutingSpec {
"age" -> BodyPart(marshalUnsafe(<int>42</int>)),
"VIP" -> BodyPart(HttpEntity(MediaTypes.`text/html`, "<b>yes</b>")))
}
val multipartFormWithFile = MultipartFormData(Seq(
BodyPart(marshalUnsafe(<int>42</int>), Seq(HttpHeaders.`Content-Disposition`("form-data", Map("filename" -> "age.xml", "name" -> "file"))))))
"The 'formFields' extraction directive" should {
"properly extract the value of www-urlencoded form fields (using the general HList-based variant)" in {
@@ -77,6 +77,13 @@ class FormFieldDirectivesSpec extends RoutingSpec {
}
} ~> check { responseAs[String] === "Mike<int>42</int>None<b>yes</b>" }
}
"extract an uploaded FormFile from multipart form fields" in {
Get("/", multipartFormWithFile) ~> {
formFields('file.as[FormFile]) { file
complete(s"type ${file.entity.contentType.mediaRange} length ${file.entity.data.length} filename ${file.name.get}")
}
} ~> check { responseAs[String] === "type text/xml length 13 filename age.xml" }
}
"reject the request with a MissingFormFieldRejection if a required form field is missing" in {
Get("/", urlEncodedForm) ~> {
formFields('firstName, "age", 'sex, "VIP" ? false) { (firstName, age, sex, vip)

0 comments on commit ae17d18

Please sign in to comment.