=htc #20793 make Marshaller.fromStatusCode emit empty entity for StatusCode with allowEntity=false

This commit is contained in:
gosubpl 2016-09-07 19:12:42 +02:00 committed by Johannes Rudolph
parent f5f37fbc39
commit 7bcf0285a1
5 changed files with 49 additions and 13 deletions

View file

@ -107,7 +107,7 @@ object StatusCodes extends ObjectRegistry[Int, StatusCode] {
val Created = reg(s(201)("Created", "The request has been fulfilled and resulted in a new resource being created."))
val Accepted = reg(s(202)("Accepted", "The request has been accepted for processing, but the processing has not been completed."))
val NonAuthoritativeInformation = reg(s(203)("Non-Authoritative Information", "The server successfully processed the request, but is returning information that may be from another source."))
val NoContent = reg(s(204)("No Content", "", allowsEntity = false))
val NoContent = reg(s(204)("No Content", "The server successfully processed the request and is not returning any content.", allowsEntity = false))
val ResetContent = reg(s(205)("Reset Content", "The server successfully processed the request, but is not returning any content."))
val PartialContent = reg(s(206)("Partial Content", "The server is delivering only part of the resource due to a range header sent by the client."))
val MultiStatus = reg(s(207)("Multi-Status", "The message body that follows is an XML message and can contain a number of separate response codes, depending on how many sub-requests were made."))

View file

@ -5,10 +5,10 @@
package akka.http.scaladsl.testkit
import scala.concurrent.duration._
import scala.concurrent.{ ExecutionContext, Await }
import akka.http.scaladsl.unmarshalling.{ Unmarshal, FromEntityUnmarshaller }
import scala.concurrent.{ Await, ExecutionContext }
import akka.http.scaladsl.unmarshalling.{ FromEntityUnmarshaller, Unmarshal }
import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.model.HttpEntity
import akka.http.scaladsl.model.{ HttpEntity, HttpRequest, HttpResponse }
import akka.stream.Materializer
import scala.util.Try
@ -17,6 +17,10 @@ trait MarshallingTestUtils {
def marshal[T: ToEntityMarshaller](value: T)(implicit ec: ExecutionContext, mat: Materializer): HttpEntity.Strict =
Await.result(Marshal(value).to[HttpEntity].flatMap(_.toStrict(1.second)), 1.second)
def marshalToResponse[T: ToResponseMarshaller](value: T, request: HttpRequest = HttpRequest())(implicit ec: ExecutionContext, mat: Materializer): HttpResponse = {
Await.result(Marshal(value).toResponseFor(request), 1.second)
}
def unmarshalValue[T: FromEntityUnmarshaller](entity: HttpEntity)(implicit ec: ExecutionContext, mat: Materializer): T =
unmarshal(entity).get

View file

@ -23,7 +23,7 @@ class MarshallingSpec extends FreeSpec with Matchers with BeforeAndAfterAll with
implicit val materializer = ActorMaterializer()
import system.dispatcher
"The PredefinedToEntityMarshallers." - {
"The PredefinedToEntityMarshallers" - {
"StringMarshaller should marshal strings to `text/plain` content in UTF-8" in {
marshal("Ha“llo") shouldEqual HttpEntity("Ha“llo")
}
@ -39,7 +39,17 @@ class MarshallingSpec extends FreeSpec with Matchers with BeforeAndAfterAll with
}
}
"The GenericMarshallers." - {
"The PredefinedToResponseMarshallers" - {
"fromStatusCode should properly marshal entities that are not supposed to have a body" in {
marshalToResponse(StatusCodes.NoContent) shouldEqual HttpResponse(StatusCodes.NoContent, entity = HttpEntity.Empty)
}
"fromStatusCode should properly marshal entities that contain pre-defined content" in {
marshalToResponse(StatusCodes.EnhanceYourCalm) shouldEqual
HttpResponse(StatusCodes.EnhanceYourCalm, entity = HttpEntity(StatusCodes.EnhanceYourCalm.defaultMessage))
}
}
"The GenericMarshallers" - {
"optionMarshaller should enable marshalling of Option[T]" in {
marshal(Some("Ha“llo")) shouldEqual HttpEntity("Ha“llo")
@ -51,7 +61,7 @@ class MarshallingSpec extends FreeSpec with Matchers with BeforeAndAfterAll with
}
}
"The MultipartMarshallers." - {
"The MultipartMarshallers" - {
"multipartMarshaller should correctly marshal multipart content with" - {
"one empty part" in {
marshal(Multipart.General(`multipart/mixed`, Multipart.General.BodyPart.Strict(""))) shouldEqual HttpEntity(

View file

@ -478,6 +478,27 @@ class CodingDirectivesSpec extends RoutingSpec with Inside {
}
}
"the default marshaller" should {
"allow compressed responses with no body for informational messages" in {
Get() ~> `Accept-Encoding`(HttpEncodings.compress) ~> {
encodeResponse {
complete { StatusCodes.Continue }
}
} ~> check {
status shouldBe StatusCodes.Continue
}
}
"allow gzipped responses with no body for 204 messages" in {
Get() ~> `Accept-Encoding`(HttpEncodings.gzip) ~> {
encodeResponse {
complete { StatusCodes.NoContent }
}
} ~> check {
status shouldBe StatusCodes.NoContent
}
}
}
def compress(input: String, encoder: Encoder): ByteString = {
val compressor = encoder.newCompressor
compressor.compressAndFlush(ByteString(input)) ++ compressor.finish()

View file

@ -5,17 +5,15 @@
package akka.http.scaladsl.marshalling
import akka.http.scaladsl.common.EntityStreamingSupport
import akka.stream.impl.ConstantFun
import scala.collection.immutable
import akka.http.scaladsl.util.FastFuture._
import akka.http.scaladsl.model.MediaTypes._
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.ContentNegotiator
import akka.http.scaladsl.util.FastFuture
import akka.http.scaladsl.util.FastFuture._
import akka.stream.impl.ConstantFun
import akka.stream.scaladsl.Source
import akka.util.ByteString
import scala.collection.immutable
import scala.language.higherKinds
trait PredefinedToResponseMarshallers extends LowPriorityToResponseMarshallerImplicits {
@ -33,7 +31,10 @@ trait PredefinedToResponseMarshallers extends LowPriorityToResponseMarshallerImp
implicit val fromStatusCode: TRM[StatusCode] =
Marshaller.withOpenCharset(`text/plain`) { (status, charset)
HttpResponse(status, entity = HttpEntity(ContentType(`text/plain`, charset), status.defaultMessage))
val responseEntity =
if (status.allowsEntity) HttpEntity(status.defaultMessage)
else HttpEntity.Empty
HttpResponse(status, entity = responseEntity)
}
implicit def fromStatusCodeAndValue[S, T](implicit sConv: S StatusCode, mt: ToEntityMarshaller[T]): TRM[(S, T)] =