+htc #17680 add HttpEntity.contentLengthOption

This commit is contained in:
Johannes Rudolph 2015-06-08 15:21:51 +02:00
parent 446a616064
commit a20f889ecb
3 changed files with 40 additions and 3 deletions

View file

@ -5,6 +5,7 @@
package akka.http.javadsl.model;
import akka.http.scaladsl.model.HttpEntity$;
import akka.japi.Option;
import akka.stream.javadsl.Source;
import akka.util.ByteString;
@ -70,6 +71,11 @@ public interface HttpEntity {
*/
public abstract boolean isIndefiniteLength();
/**
* Returns Some(contentLength) if the length is defined and none otherwise.
*/
public abstract Option<Long> getContentLengthOption();
/**
* Returns a stream of data bytes this entity consists of.
*/

View file

@ -6,15 +6,15 @@ package akka.http.scaladsl.model
import language.implicitConversions
import java.io.File
import java.lang.{ Iterable JIterable }
import java.lang.{ Iterable JIterable, Long JLong }
import scala.concurrent.Future
import scala.concurrent.duration.FiniteDuration
import scala.collection.immutable
import akka.util.ByteString
import akka.stream.FlowMaterializer
import akka.stream.scaladsl._
import akka.stream
import akka.stream.io.SynchronousFileSource
import akka.{ japi, stream }
import akka.stream.TimerTransformer
import akka.http.scaladsl.util.FastFuture
import akka.http.javadsl.{ model jm }
@ -34,6 +34,16 @@ sealed trait HttpEntity extends jm.HttpEntity {
*/
def contentType: ContentType
/**
* Some(content length) if a length is defined for this entity, None otherwise.
* A length is only defined for Strict and Default entity types.
*
* In many cases it's dangerous to rely on the (non-)existence of a content-length.
* HTTP intermediaries like (transparent) proxies are allowed to change the transfer-encoding
* which can result in the entity being delivered as another type as expected.
*/
def contentLengthOption: Option[Long]
/**
* A stream of the data of this entity.
*/
@ -84,6 +94,10 @@ sealed trait HttpEntity extends jm.HttpEntity {
/** Java API */
def getDataBytes: stream.javadsl.Source[ByteString, _] = stream.javadsl.Source.adapt(dataBytes)
/** Java API */
def getContentLengthOption: japi.Option[JLong] =
japi.Option.fromScalaOption(contentLengthOption.asInstanceOf[Option[JLong]]) // Scala autoboxing
// default implementations, should be overridden
def isCloseDelimited: Boolean = false
def isIndefiniteLength: Boolean = false
@ -111,6 +125,7 @@ sealed trait ResponseEntity extends HttpEntity with jm.ResponseEntity {
sealed trait UniversalEntity extends jm.UniversalEntity with MessageEntity with BodyPartEntity {
def withContentType(contentType: ContentType): UniversalEntity
def contentLength: Long
def contentLengthOption: Option[Long] = Some(contentLength)
/**
* Transforms this' entities data bytes with a transformer that will produce exactly the number of bytes given as
@ -181,7 +196,6 @@ object HttpEntity {
contentLength: Long,
data: Source[ByteString, Any])
extends jm.HttpEntityDefault with UniversalEntity {
require(contentLength > 0, "contentLength must be positive (use `HttpEntity.empty(contentType)` for empty entities)")
def isKnownEmpty = false
override def isDefault: Boolean = true
@ -208,6 +222,7 @@ object HttpEntity {
private[http] sealed trait WithoutKnownLength extends HttpEntity {
def contentType: ContentType
def data: Source[ByteString, Any]
def contentLengthOption: Option[Long] = None
def isKnownEmpty = data eq Source.empty
@ -257,6 +272,8 @@ object HttpEntity {
extends jm.HttpEntityChunked with MessageEntity {
def isKnownEmpty = chunks eq Source.empty
def contentLengthOption: Option[Long] = None
override def isChunked: Boolean = true
def dataBytes: Source[ByteString, Any] = chunks.map(_.data).filter(_.nonEmpty)

View file

@ -51,6 +51,20 @@ class HttpEntitySpec extends FreeSpec with MustMatchers with BeforeAndAfterAll {
Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)) must collectBytesTo(abc, fgh, ijk)
}
}
"support contentLength" - {
"Strict" in {
Strict(tpe, abc).contentLengthOption mustEqual Some(3)
}
"Default" in {
Default(tpe, 11, source(abc, de, fgh, ijk)).contentLengthOption mustEqual Some(11)
}
"CloseDelimited" in {
CloseDelimited(tpe, source(abc, de, fgh, ijk)).contentLengthOption mustEqual None
}
"Chunked" in {
Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk))).contentLengthOption mustEqual None
}
}
"support toStrict" - {
"Strict" in {
Strict(tpe, abc) must strictifyTo(Strict(tpe, abc))