Merge pull request #20343 from TrustNoOne/20342-support-httpentity-withSizeLimit

support HttpEntity.with/withoutSizeLimit in scaladsl HttpEntity
This commit is contained in:
Johan Andrén 2016-04-21 11:49:26 +02:00
commit fd89f36940
3 changed files with 75 additions and 1 deletions

View file

@ -86,6 +86,45 @@ sealed trait HttpEntity extends jm.HttpEntity {
*/
def withContentType(contentType: ContentType): HttpEntity
/**
* Apply the given size limit to this entity by returning a new entity instance which automatically verifies that the
* data stream encapsulated by this instance produces at most `maxBytes` data bytes. In case this verification fails
* the respective stream will be terminated with an `EntityStreamException` either directly at materialization
* time (if the Content-Length is known) or whenever more data bytes than allowed have been read.
*
* When called on `Strict` entities the method will return the entity itself if the length is within the bound,
* otherwise a `Default` entity with a single element data stream. This allows for potential refinement of the
* entity size limit at a later point (before materialization of the data stream).
*
* By default all message entities produced by the HTTP layer automatically carry the limit that is defined in the
* application's `max-content-length` config setting. If the entity is transformed in a way that changes the
* Content-Length and then another limit is applied then this new limit will be evaluated against the new
* Content-Length. If the entity is transformed in a way that changes the Content-Length and no new limit is applied
* then the previous limit will be applied against the previous Content-Length.
*
* Note that the size limit applied via this method will only have any effect if the `Source` instance contained
* in this entity has been appropriately modified via the `HttpEntity.limitable` method. For all entities created
* by the HTTP layer itself this is always the case, but if you create entities yourself and would like them to
* properly respect limits defined via this method you need to make sure to apply `HttpEntity.limitable` yourself.
*/
override def withSizeLimit(maxBytes: Long): HttpEntity
/**
* Lift the size limit from this entity by returning a new entity instance which skips the size verification.
*
* By default all message entities produced by the HTTP layer automatically carry the limit that is defined in the
* application's `max-content-length` config setting. It is recommended to always keep an upper limit on accepted
* entities to avoid potential attackers flooding you with too large requests/responses, so use this method with caution.
*
* Note that the size limit applied via this method will only have any effect if the `Source` instance contained
* in this entity has been appropriately modified via the `HttpEntity.limitable` method. For all entities created
* by the HTTP layer itself this is always the case, but if you create entities yourself and would like them to
* properly respect limits defined via this method you need to make sure to apply `HttpEntity.limitable` yourself.
*
* See [[withSizeLimit]] for more details.
*/
override def withoutSizeLimit: HttpEntity
/** Java API */
override def getContentType: jm.ContentType = contentType

View file

@ -157,20 +157,50 @@ class HttpEntitySpec extends FreeSpec with MustMatchers with BeforeAndAfterAll {
withReturnType[UniversalEntity](Strict(tpe, abc).withoutSizeLimit)
withReturnType[RequestEntity](Strict(tpe, abc).asInstanceOf[RequestEntity].withoutSizeLimit)
withReturnType[ResponseEntity](Strict(tpe, abc).asInstanceOf[ResponseEntity].withoutSizeLimit)
withReturnType[HttpEntity](Strict(tpe, abc).asInstanceOf[HttpEntity].withoutSizeLimit)
}
"Default" in {
withReturnType[Default](Default(tpe, 11, source(abc, de, fgh, ijk)).withoutSizeLimit)
withReturnType[RequestEntity](Default(tpe, 11, source(abc, de, fgh, ijk)).asInstanceOf[RequestEntity].withoutSizeLimit)
withReturnType[ResponseEntity](Default(tpe, 11, source(abc, de, fgh, ijk)).asInstanceOf[ResponseEntity].withoutSizeLimit)
withReturnType[HttpEntity](Default(tpe, 11, source(abc, de, fgh, ijk)).asInstanceOf[HttpEntity].withoutSizeLimit)
}
"CloseDelimited" in {
withReturnType[CloseDelimited](CloseDelimited(tpe, source(abc, de, fgh, ijk)).withoutSizeLimit)
withReturnType[ResponseEntity](CloseDelimited(tpe, source(abc, de, fgh, ijk)).asInstanceOf[ResponseEntity].withoutSizeLimit)
withReturnType[HttpEntity](CloseDelimited(tpe, source(abc, de, fgh, ijk)).asInstanceOf[HttpEntity].withoutSizeLimit)
}
"Chunked" in {
withReturnType[Chunked](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).withoutSizeLimit)
withReturnType[RequestEntity](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).asInstanceOf[RequestEntity].withoutSizeLimit)
withReturnType[ResponseEntity](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).asInstanceOf[ResponseEntity].withoutSizeLimit)
withReturnType[HttpEntity](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).asInstanceOf[HttpEntity].withoutSizeLimit)
}
}
"support withSizeLimit" - {
"Strict" in {
HttpEntity.Empty.withSizeLimit(123L)
withReturnType[UniversalEntity](Strict(tpe, abc).withSizeLimit(123L))
withReturnType[RequestEntity](Strict(tpe, abc).asInstanceOf[RequestEntity].withSizeLimit(123L))
withReturnType[ResponseEntity](Strict(tpe, abc).asInstanceOf[ResponseEntity].withSizeLimit(123L))
withReturnType[HttpEntity](Strict(tpe, abc).asInstanceOf[HttpEntity].withSizeLimit(123L))
}
"Default" in {
withReturnType[Default](Default(tpe, 11, source(abc, de, fgh, ijk)).withoutSizeLimit)
withReturnType[RequestEntity](Default(tpe, 11, source(abc, de, fgh, ijk)).asInstanceOf[RequestEntity].withSizeLimit(123L))
withReturnType[ResponseEntity](Default(tpe, 11, source(abc, de, fgh, ijk)).asInstanceOf[ResponseEntity].withSizeLimit(123L))
withReturnType[HttpEntity](Default(tpe, 11, source(abc, de, fgh, ijk)).asInstanceOf[HttpEntity].withSizeLimit(123L))
}
"CloseDelimited" in {
withReturnType[CloseDelimited](CloseDelimited(tpe, source(abc, de, fgh, ijk)).withSizeLimit(123L))
withReturnType[ResponseEntity](CloseDelimited(tpe, source(abc, de, fgh, ijk)).asInstanceOf[ResponseEntity].withSizeLimit(123L))
withReturnType[HttpEntity](CloseDelimited(tpe, source(abc, de, fgh, ijk)).asInstanceOf[HttpEntity].withSizeLimit(123L))
}
"Chunked" in {
withReturnType[Chunked](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).withSizeLimit(123L))
withReturnType[RequestEntity](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).asInstanceOf[RequestEntity].withSizeLimit(123L))
withReturnType[ResponseEntity](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).asInstanceOf[ResponseEntity].withSizeLimit(123L))
withReturnType[HttpEntity](Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)).asInstanceOf[HttpEntity].withSizeLimit(123L))
}
}
}

View file

@ -742,7 +742,12 @@ object MiMa extends AutoPlugin {
// #20123
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.stream.scaladsl.FlowOps.recoverWithRetries")
)
),
"2.4.4" -> Seq(
// #20342 HttpEntity scaladsl overrides
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.model.HttpEntity.withoutSizeLimit"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.model.HttpEntity.withSizeLimit")
)
)
}
}