diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala index ab66c92a98..fb8426b77f 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala @@ -47,6 +47,14 @@ class MarshallingSpec extends FreeSpec with Matchers with BeforeAndAfterAll with marshalToResponse(StatusCodes.EnhanceYourCalm) shouldEqual HttpResponse(StatusCodes.EnhanceYourCalm, entity = HttpEntity(StatusCodes.EnhanceYourCalm.defaultMessage)) } + "fromStatusCodeAndHeadersAndValue should properly marshal entities that are not supposed to have a body" in { + marshalToResponse((StatusCodes.NoContent, "This Content was intentionally left blank.")) shouldEqual + HttpResponse(StatusCodes.NoContent, entity = HttpEntity.Empty) + } + "fromStatusCodeAndHeadersAndValue should properly marshal entities that contain pre-defined content" in { + marshalToResponse((StatusCodes.EnhanceYourCalm, "Patience, young padawan!")) shouldEqual + HttpResponse(StatusCodes.EnhanceYourCalm, entity = HttpEntity("Patience, young padawan!")) + } } "The GenericMarshallers" - { 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 fa52405e97..12024906ae 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 @@ -176,6 +176,29 @@ class CodingDirectivesSpec extends RoutingSpec with Inside { encodeResponseWith(Deflate) { nope } } ~> check { strictify(responseEntity) shouldEqual HttpEntity(ContentType(`text/plain`, `UTF-8`), nopeDeflated) } } + "not encode the response content with GZIP if the response is of status not allowing entity" in { + Post() ~> { + encodeResponseWith(Gzip) { complete { StatusCodes.NoContent } } + } ~> check { + response should haveNoContentEncoding + response shouldEqual HttpResponse(StatusCodes.NoContent, entity = HttpEntity.Empty) + } + } + "not encode the response content with Deflate if the response is of status not allowing entity" in { + Post() ~> { + encodeResponseWith(Deflate) { complete((100, "Let's continue!")) } + } ~> check { + response should haveNoContentEncoding + response shouldEqual HttpResponse(StatusCodes.Continue, entity = HttpEntity.Empty) + } + } + "encode the response content with GZIP if the response is of status allowing entity" in { + Post() ~> { + encodeResponseWith(Gzip) { nope } + } ~> check { + response should haveContentEncoding(gzip) + } + } } "the Gzip encoder" should { diff --git a/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala b/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala index 6204cd8927..0f6a0e2af1 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala @@ -43,7 +43,10 @@ trait Encoder { } object Encoder { - val DefaultFilter: HttpMessage ⇒ Boolean = isCompressible _ + val DefaultFilter: HttpMessage ⇒ Boolean = { + case req: HttpRequest ⇒ isCompressible(req) + case res @ HttpResponse(status, _, _, _) ⇒ isCompressible(res) && status.allowsEntity + } private[coding] def isCompressible(msg: HttpMessage): Boolean = msg.entity.contentType.mediaType.isCompressible diff --git a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToResponseMarshallers.scala b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToResponseMarshallers.scala index 49ff565a37..d587566a20 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToResponseMarshallers.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToResponseMarshallers.scala @@ -37,6 +37,16 @@ trait PredefinedToResponseMarshallers extends LowPriorityToResponseMarshallerImp HttpResponse(status, entity = responseEntity) } + implicit val fromStatusCodeAndHeaders: TRM[(StatusCode, immutable.Seq[HttpHeader])] = + Marshaller.withOpenCharset(`text/plain`) { (statusAndHeaders, charset) ⇒ + val status = statusAndHeaders._1 + val headers = statusAndHeaders._2 + val responseEntity = + if (status.allowsEntity) HttpEntity(status.defaultMessage) + else HttpEntity.Empty + HttpResponse(status, headers, entity = responseEntity) + } + implicit def fromStatusCodeAndValue[S, T](implicit sConv: S ⇒ StatusCode, mt: ToEntityMarshaller[T]): TRM[(S, T)] = fromStatusCodeAndHeadersAndValue[T] compose { case (status, value) ⇒ (sConv(status), Nil, value) } @@ -47,7 +57,8 @@ trait PredefinedToResponseMarshallers extends LowPriorityToResponseMarshallerImp implicit def fromStatusCodeAndHeadersAndValue[T](implicit mt: ToEntityMarshaller[T]): TRM[(StatusCode, immutable.Seq[HttpHeader], T)] = Marshaller(implicit ec ⇒ { - case (status, headers, value) ⇒ mt(value).fast map (_ map (_ map (HttpResponse(status, headers, _)))) + case (status, headers, value) if (status.allowsEntity) ⇒ mt(value).fast map (_ map (_ map (HttpResponse(status, headers, _)))) + case (status, headers, _) ⇒ fromStatusCodeAndHeaders((status, headers)) }) implicit def fromEntityStreamingSupportAndByteStringMarshaller[T, M](implicit s: EntityStreamingSupport, m: ToByteStringMarshaller[T]): ToResponseMarshaller[Source[T, M]] = {