From 3ef074d1ec47308122ff17ed21fc0d24a13b4c88 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 31 Aug 2015 12:05:12 +0200 Subject: [PATCH] =htp #17068 decodeRequestWith(NoEncoding) should not touch request entity --- .../directives/CodingDirectivesSpec.scala | 52 +++++++++++++++++-- .../server/directives/CodingDirectives.scala | 22 ++++---- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/CodingDirectivesSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/CodingDirectivesSpec.scala index f6cd19e114..8049e196d2 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/CodingDirectivesSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/CodingDirectivesSpec.scala @@ -5,9 +5,10 @@ package akka.http.scaladsl.server package directives +import org.scalatest.Inside import org.scalatest.matchers.Matcher import akka.util.ByteString -import akka.stream.scaladsl.Source +import akka.stream.scaladsl.{ Sink, Source } import akka.http.impl.util._ import akka.http.scaladsl.model._ import akka.http.scaladsl.coding._ @@ -17,10 +18,11 @@ import HttpCharsets._ import HttpEncodings._ import MediaTypes._ import StatusCodes._ +import ContentTypes.`application/octet-stream` import scala.concurrent.duration._ -class CodingDirectivesSpec extends RoutingSpec { +class CodingDirectivesSpec extends RoutingSpec with Inside { val echoRequestContent: Route = { ctx ⇒ ctx.complete(ctx.request.entity.dataBytes.utf8String) } @@ -46,7 +48,51 @@ class CodingDirectivesSpec extends RoutingSpec { Post("/", "yes") ~> decodeRequestWith(NoCoding) { echoRequestContent } ~> check { responseAs[String] shouldEqual "yes" } } "leave request without content unchanged" in { - Post() ~> decodeRequestWith(Gzip) { completeOk } ~> check { response shouldEqual Ok } + Post() ~> decodeRequestWith(NoCoding) { completeOk } ~> check { response shouldEqual Ok } + } + + val echoDecodedEntity = + decodeRequestWith(NoCoding) { + extractRequest { request ⇒ + complete(HttpResponse(200, entity = request.entity)) + } + } + "leave Strict request entity unchanged" in { + val data = ByteString(Array.fill[Byte](10000)(42.toByte)) + val strictEntity = HttpEntity.Strict(`application/octet-stream`, data) + + Post("/", strictEntity) ~> echoDecodedEntity ~> check { + responseEntity shouldEqual strictEntity + } + } + "leave Default request entity unchanged" in { + val chunks = Vector(ByteString("abc"), ByteString("def"), ByteString("ghi")) + val data = Source(chunks) + + val defaultEntity = HttpEntity.Default(`application/octet-stream`, 9, data) + + Post("/", defaultEntity) ~> echoDecodedEntity ~> check { + inside(responseEntity) { + case HttpEntity.Default(`application/octet-stream`, 9, dataChunks) ⇒ + dataChunks.grouped(1000).runWith(Sink.head).awaitResult(1.second).toVector shouldEqual chunks + } + } + } + // CloseDelimited not support for requests + "leave Chunked request entity unchanged" in { + val chunks = + Vector(ByteString("abc"), ByteString("def"), ByteString("ghi")) + .map(ChunkStreamPart(_)) + val data = Source(chunks) + + val defaultEntity = HttpEntity.Chunked(`application/octet-stream`, data) + + Post("/", defaultEntity) ~> echoDecodedEntity ~> check { + inside(responseEntity) { + case HttpEntity.Chunked(`application/octet-stream`, dataChunks) ⇒ + dataChunks.grouped(1000).runWith(Sink.head).awaitResult(1.second).toVector shouldEqual chunks + } + } } } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala index b5325ae560..0f9531e4e2 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala @@ -62,17 +62,19 @@ trait CodingDirectives { */ def decodeRequestWith(decoder: Decoder): Directive0 = { def applyDecoder = - extractSettings flatMap { settings ⇒ - val effectiveDecoder = decoder.withMaxBytesPerChunk(settings.decodeMaxBytesPerChunk) - mapRequest { request ⇒ - effectiveDecoder.decode(request).mapEntity(StreamUtils.mapEntityError { - case NonFatal(e) ⇒ - IllegalRequestException( - StatusCodes.BadRequest, - ErrorInfo("The request's encoding is corrupt", e.getMessage)) - }) + if (decoder == NoCoding) pass + else + extractSettings flatMap { settings ⇒ + val effectiveDecoder = decoder.withMaxBytesPerChunk(settings.decodeMaxBytesPerChunk) + mapRequest { request ⇒ + effectiveDecoder.decode(request).mapEntity(StreamUtils.mapEntityError { + case NonFatal(e) ⇒ + IllegalRequestException( + StatusCodes.BadRequest, + ErrorInfo("The request's encoding is corrupt", e.getMessage)) + }) + } } - } requestEntityEmpty | ( requestEncodedWith(decoder.encoding) &