Skip to content

Commit

Permalink
Merge pull request #2276 from jkyamog/master
Browse files Browse the repository at this point in the history
First 2 bytes of http headers getting dropped on some http client
  • Loading branch information
huntc committed Feb 25, 2014
2 parents 16bf844 + 85d4308 commit 0949808
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 2 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -632,9 +632,9 @@ trait BodyParsers {
val maxHeaderBuffer = Traversable.takeUpTo[Array[Byte]](4 * 1024) transform Iteratee.consume[Array[Byte]]() val maxHeaderBuffer = Traversable.takeUpTo[Array[Byte]](4 * 1024) transform Iteratee.consume[Array[Byte]]()


val collectHeaders = maxHeaderBuffer.map { buffer => val collectHeaders = maxHeaderBuffer.map { buffer =>
val (headerBytes, rest) = Option(buffer.drop(2)).map(b => b.splitAt(b.indexOfSlice(CRLFCRLF))).get val (headerBytes, rest) = Option(buffer).map(b => b.splitAt(b.indexOfSlice(CRLFCRLF))).get


val headerString = new String(headerBytes, "utf-8") val headerString = new String(headerBytes, "utf-8").trim
val headers = headerString.lines.map { header => val headers = headerString.lines.map { header =>
val key :: value = header.trim.split(":").toList val key :: value = header.trim.split(":").toList
(key.trim.toLowerCase, value.mkString.trim) (key.trim.toLowerCase, value.mkString.trim)
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ package play.api.mvc


import org.specs2.mutable.Specification import org.specs2.mutable.Specification
import scalax.io.Resource import scalax.io.Resource
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.duration._
import play.api.libs.iteratee.Enumerator


object ContentTypesSpec extends Specification { object ContentTypesSpec extends Specification {


Expand Down Expand Up @@ -93,5 +97,48 @@ object ContentTypesSpec extends Specification {
Resource.fromFile(file).string must_== "hello world" Resource.fromFile(file).string must_== "hello world"
} }
} }

"Multipart parser" should {

"get the file parts" in {
testMultiPart("-----------------------------117723558510316372842092349957\r\nContent-Disposition: form-data; name=\"picture\"; filename=\"README\"\r\nContent-Type: application/octet-stream\r\n\r\nThis is your new Play application\r\n=====================================\r\nThis file will be packaged with your application, when using `play dist`.\r\n-----------------------------117723558510316372842092349957--\r\n")
}

"get the file parts with boundary that has no CRLF at start" in {
testMultiPart("-----------------------------117723558510316372842092349957Content-Disposition: form-data; name=\"picture\"; filename=\"README\"\r\nContent-Type: application/octet-stream\r\n\r\nThis is your new Play application\r\n=====================================\r\nThis file will be packaged with your application, when using `play dist`.\r\n-----------------------------117723558510316372842092349957--\r\n")
}

def testMultiPart(testMultipartBody: String) = {

def await[T](f: Future[T]) = Await.result(f, Duration("5 seconds"))
case class TestRequestHeader(headers: Headers, method: String = "GET", uri: String = "/", path: String = "", remoteAddress: String = "127.0.0.1", version: String = "HTTP/1.1", id: Long = 1, tags: Map[String, String] = Map.empty[String, String], queryString: Map[String, Seq[String]] = Map(), secure: Boolean = false) extends RequestHeader
val multipartFormDataParser = BodyParsers.parse.multipartFormData

val rh = TestRequestHeader(headers = new Headers {
val data = Seq(play.api.http.HeaderNames.CONTENT_TYPE -> Seq("multipart/form-data; boundary=---------------------------117723558510316372842092349957"), play.api.http.HeaderNames.CONTENT_LENGTH -> Seq("382"))
})

val body = Enumerator(testMultipartBody.getBytes)
val parsedResult = await(body run multipartFormDataParser(rh))

parsedResult.isRight must beTrue

parsedResult match {
case Right(multipartFormData) =>
multipartFormData.badParts.isEmpty must beTrue
multipartFormData.missingFileParts.isEmpty must beTrue
multipartFormData.dataParts.isEmpty must beTrue

multipartFormData.files.size must_== 1
val filePart = multipartFormData.files.head
filePart.filename must_== "README"
filePart.contentType must beSome("application/octet-stream")
filePart.key must_== "picture"
success
case Left(_) =>
failure("must not get a Left result")
}
}
}
} }


0 comments on commit 0949808

Please sign in to comment.