akka/akka-http

Corresponding coding directives fail to process gzip- and deflate-compressed HTTP/1.0 requests

Open

#46 opened on Sep 8, 2016

View on GitHub
 (7 comments) (0 reactions) (0 assignees)Scala (598 forks)batch import
1 - triageddiscusshelp wanted

Repository metrics

Stars
 (1,311 stars)
PR merge metrics
 (Avg merge 1d 10h) (2 merged PRs in 30d)

Description

Issue by levkhomich Saturday Jul 16, 2016 at 06:40 GMT Originally opened as https://github.com/akka/akka/issues/20969


The problem is that decodeRequest and decodeRequestWith directives map original request entity to HttpEntity.Chunked which, in turn, fails HttpRequest.copy's requirement

require(
    protocol == HttpProtocols.`HTTP/1.1` || !entity.isInstanceOf[HttpEntity.Chunked],
    "HTTP/1.0 responses must not have a chunked entity")

and produces following stack trace:

java.lang.IllegalArgumentException: requirement failed: HTTP/1.0 requests must not have a chunked entity
    at scala.Predef$.require(Predef.scala:224)
    at akka.http.scaladsl.model.HttpRequest.<init>(HttpMessage.scala:207)
    at akka.http.scaladsl.model.HttpRequest.copy(HttpMessage.scala:271)
    at akka.http.scaladsl.coding.DataMapper$$anonfun$1.apply(DataMapper.scala:32)
    at akka.http.scaladsl.coding.DataMapper$$anonfun$1.apply(DataMapper.scala:28)
    at akka.http.scaladsl.coding.DataMapper$$anon$3.transformDataBytes(DataMapper.scala:41)
    at akka.http.scaladsl.coding.Decoder$class.decodeData(Decoder.scala:25)
    at akka.http.scaladsl.coding.StreamDecoder$$anon$1.decodeData(Decoder.scala:44)
    at akka.http.scaladsl.coding.Decoder$class.decode(Decoder.scala:22)
    at akka.http.scaladsl.coding.StreamDecoder$$anon$1.decode(Decoder.scala:44)
    at akka.http.scaladsl.server.directives.CodingDirectives$$anonfun$applyDecoder$1$1$$anonfun$apply$2.apply(CodingDirectives.scala:86)
    at akka.http.scaladsl.server.directives.CodingDirectives$$anonfun$applyDecoder$1$1$$anonfun$apply$2.apply(CodingDirectives.scala:85)

Steps to reproduce. Test case:

  val echoRequestContent: Route = { ctx ⇒ ctx.complete(ctx.request.entity.dataBytes.utf8String) }
  lazy val helloGzipped = compress("Hello", Gzip)
  def compress(input: String, encoder: Encoder): ByteString = {
    val compressor = encoder.newCompressor
    compressor.compressAndFlush(ByteString(input)) ++ compressor.finish()
  }

  "decode HTTP/1.0 request with 'gzip' encoding" in {
    HttpRequest(POST, Uri("/"), entity = HttpEntity(helloGzipped), protocol = `HTTP/1.0`) ~> `Content-Encoding`(gzip) ~> {
      decodeRequestWith(Gzip) { echoRequestContent }
    } ~> check { responseAs[String] shouldEqual "Hello" }
  }

Contributor guide