!htc restructure HttpEntity model on the Java side for consistency in modelling approach
This commit is contained in:
parent
42b694fa7b
commit
902bcbaa10
11 changed files with 179 additions and 198 deletions
|
|
@ -156,7 +156,7 @@ public class HttpServerExampleDocTest {
|
|||
.via(failureDetection)
|
||||
.map(request -> {
|
||||
Source<ByteString, Object> bytes = request.entity().getDataBytes();
|
||||
HttpEntityChunked entity = HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, bytes);
|
||||
HttpEntity.Chunked entity = HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, bytes);
|
||||
|
||||
return HttpResponse.create()
|
||||
.withEntity(entity);
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
import akka.http.impl.util.Util;
|
||||
import akka.http.scaladsl.model.HttpEntity;
|
||||
import akka.util.ByteString;
|
||||
|
||||
/**
|
||||
* Represents part of a stream of incoming data for `Transfer-Encoding: chunked` messages.
|
||||
*/
|
||||
public abstract class ChunkStreamPart {
|
||||
/**
|
||||
* Returns the byte data of this chunk. Will be non-empty for every regular
|
||||
* chunk. Will be empty for the last chunk.
|
||||
*/
|
||||
public abstract ByteString data();
|
||||
|
||||
/**
|
||||
* Returns extensions data for this chunk.
|
||||
*/
|
||||
public abstract String extension();
|
||||
|
||||
/**
|
||||
* Returns if this is the last chunk
|
||||
*/
|
||||
public abstract boolean isLastChunk();
|
||||
|
||||
/**
|
||||
* If this is the last chunk, this will return an Iterable of the trailer headers. Otherwise,
|
||||
* it will be empty.
|
||||
*/
|
||||
public abstract Iterable<HttpHeader> getTrailerHeaders();
|
||||
|
||||
/**
|
||||
* Creates a chunk from data and extension.
|
||||
*/
|
||||
public static ChunkStreamPart create(ByteString data, String extension) {
|
||||
return new HttpEntity.Chunk(data, extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chunk from data with an empty extension.
|
||||
*/
|
||||
public static ChunkStreamPart create(ByteString data) {
|
||||
return create(data, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* The default last ChunkStreamPart that has no extension and no trailer headers.
|
||||
*/
|
||||
public static final ChunkStreamPart LAST = HttpEntity.LastChunk$.MODULE$;
|
||||
|
||||
/**
|
||||
* Creates a last chunk with extension and headers.
|
||||
*/
|
||||
public static ChunkStreamPart createLast(String extension, Iterable<HttpHeader> trailerHeaders){
|
||||
return new HttpEntity.LastChunk(extension, Util.<HttpHeader, akka.http.scaladsl.model.HttpHeader>convertIterable(trailerHeaders));
|
||||
}
|
||||
}
|
||||
|
|
@ -16,27 +16,27 @@ import akka.stream.javadsl.Source;
|
|||
public final class HttpEntities {
|
||||
private HttpEntities() {}
|
||||
|
||||
public static HttpEntityStrict create(String string) {
|
||||
public static HttpEntity.Strict create(String string) {
|
||||
return HttpEntity$.MODULE$.apply(string);
|
||||
}
|
||||
|
||||
public static HttpEntityStrict create(byte[] bytes) {
|
||||
public static HttpEntity.Strict create(byte[] bytes) {
|
||||
return HttpEntity$.MODULE$.apply(bytes);
|
||||
}
|
||||
|
||||
public static HttpEntityStrict create(ByteString bytes) {
|
||||
public static HttpEntity.Strict create(ByteString bytes) {
|
||||
return HttpEntity$.MODULE$.apply(bytes);
|
||||
}
|
||||
|
||||
public static HttpEntityStrict create(ContentType.NonBinary contentType, String string) {
|
||||
public static HttpEntity.Strict create(ContentType.NonBinary contentType, String string) {
|
||||
return HttpEntity$.MODULE$.apply((akka.http.scaladsl.model.ContentType.NonBinary) contentType, string);
|
||||
}
|
||||
|
||||
public static HttpEntityStrict create(ContentType contentType, byte[] bytes) {
|
||||
public static HttpEntity.Strict create(ContentType contentType, byte[] bytes) {
|
||||
return HttpEntity$.MODULE$.apply((akka.http.scaladsl.model.ContentType) contentType, bytes);
|
||||
}
|
||||
|
||||
public static HttpEntityStrict create(ContentType contentType, ByteString bytes) {
|
||||
public static HttpEntity.Strict create(ContentType contentType, ByteString bytes) {
|
||||
return HttpEntity$.MODULE$.apply((akka.http.scaladsl.model.ContentType) contentType, bytes);
|
||||
}
|
||||
|
||||
|
|
@ -48,23 +48,23 @@ public final class HttpEntities {
|
|||
return HttpEntity$.MODULE$.apply((akka.http.scaladsl.model.ContentType) contentType, file, chunkSize);
|
||||
}
|
||||
|
||||
public static HttpEntityDefault create(ContentType contentType, long contentLength, Source<ByteString, Object> data) {
|
||||
public static HttpEntity.Default create(ContentType contentType, long contentLength, Source<ByteString, Object> data) {
|
||||
return new akka.http.scaladsl.model.HttpEntity.Default((akka.http.scaladsl.model.ContentType) contentType, contentLength, data.asScala());
|
||||
}
|
||||
|
||||
public static HttpEntityChunked create(ContentType contentType, Source<ByteString, Object> data) {
|
||||
public static HttpEntity.Chunked create(ContentType contentType, Source<ByteString, Object> data) {
|
||||
return HttpEntity.Chunked$.MODULE$.fromData((akka.http.scaladsl.model.ContentType) contentType, data.asScala());
|
||||
}
|
||||
|
||||
public static HttpEntityCloseDelimited createCloseDelimited(ContentType contentType, Source<ByteString, Object> data) {
|
||||
public static HttpEntity.CloseDelimited createCloseDelimited(ContentType contentType, Source<ByteString, Object> data) {
|
||||
return new akka.http.scaladsl.model.HttpEntity.CloseDelimited((akka.http.scaladsl.model.ContentType) contentType, data.asScala());
|
||||
}
|
||||
|
||||
public static HttpEntityIndefiniteLength createIndefiniteLength(ContentType contentType, Source<ByteString, Object> data) {
|
||||
public static HttpEntity.IndefiniteLength createIndefiniteLength(ContentType contentType, Source<ByteString, Object> data) {
|
||||
return new akka.http.scaladsl.model.HttpEntity.IndefiniteLength((akka.http.scaladsl.model.ContentType) contentType, data.asScala());
|
||||
}
|
||||
|
||||
public static HttpEntityChunked createChunked(ContentType contentType, Source<ByteString, Object> data) {
|
||||
public static HttpEntity.Chunked createChunked(ContentType contentType, Source<ByteString, Object> data) {
|
||||
return akka.http.scaladsl.model.HttpEntity.Chunked$.MODULE$.fromData(
|
||||
(akka.http.scaladsl.model.ContentType) contentType,
|
||||
data.asScala());
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
import akka.http.impl.util.Util;
|
||||
import akka.http.scaladsl.model.HttpEntity$;
|
||||
import akka.japi.Option;
|
||||
import akka.stream.Materializer;
|
||||
|
|
@ -19,13 +20,13 @@ import scala.concurrent.Future;
|
|||
* An HttpEntity can be of several kinds:
|
||||
*
|
||||
* - HttpEntity.Empty: the statically known empty entity
|
||||
* - HttpEntityStrict: an entity containing already evaluated ByteString data
|
||||
* - HttpEntityDefault: the default entity which has a known length and which contains
|
||||
* - HttpEntity.Strict: an entity containing already evaluated ByteString data
|
||||
* - HttpEntity.Default: the default entity which has a known length and which contains
|
||||
* a stream of ByteStrings.
|
||||
* - HttpEntityChunked: represents an entity that is delivered using `Transfer-Encoding: chunked`
|
||||
* - HttpEntityCloseDelimited: an entity which doesn't have a fixed length but which is delimited by
|
||||
* - HttpEntity.Chunked: represents an entity that is delivered using `Transfer-Encoding: chunked`
|
||||
* - HttpEntity.CloseDelimited: an entity which doesn't have a fixed length but which is delimited by
|
||||
* closing the connection.
|
||||
* - HttpEntityIndefiniteLength: an entity which doesn't have a fixed length which can be used to construct BodyParts
|
||||
* - HttpEntity.IndefiniteLength: an entity which doesn't have a fixed length which can be used to construct BodyParts
|
||||
* with indefinite length
|
||||
*
|
||||
* Marker-interfaces denote which subclasses can be used in which context:
|
||||
|
|
@ -40,12 +41,12 @@ public interface HttpEntity {
|
|||
/**
|
||||
* Returns the content-type of this entity
|
||||
*/
|
||||
ContentType contentType();
|
||||
ContentType getContentType();
|
||||
|
||||
/**
|
||||
* The empty entity.
|
||||
*/
|
||||
HttpEntityStrict EMPTY = HttpEntity$.MODULE$.Empty();
|
||||
HttpEntity.Strict EMPTY = HttpEntity$.MODULE$.Empty();
|
||||
|
||||
/**
|
||||
* Returns if this entity is known to be empty. Open-ended entity types like
|
||||
|
|
@ -92,5 +93,94 @@ public interface HttpEntity {
|
|||
* Use getDataBytes and stream processing instead if the expected data is big or
|
||||
* is likely to take a long time.
|
||||
*/
|
||||
Future<HttpEntityStrict> toStrict(long timeoutMillis, Materializer materializer);
|
||||
Future<HttpEntity.Strict> toStrict(long timeoutMillis, Materializer materializer);
|
||||
|
||||
/**
|
||||
* The entity type which consists of a predefined fixed ByteString of data.
|
||||
*/
|
||||
interface Strict extends UniversalEntity {
|
||||
ByteString getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default entity type which has a predetermined length and a stream of data bytes.
|
||||
*/
|
||||
interface Default extends UniversalEntity {
|
||||
long getContentLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entity without a predetermined content-length. Its length is implicitly
|
||||
* determined by closing the underlying connection. Therefore, this entity type is only
|
||||
* available for Http responses.
|
||||
*/
|
||||
interface CloseDelimited extends ResponseEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entity transferred using `Transfer-Encoding: chunked`. It consists of a
|
||||
* stream of {@link ChunkStreamPart}.
|
||||
*/
|
||||
interface Chunked extends RequestEntity, ResponseEntity {
|
||||
Source<ChunkStreamPart, Object> getChunks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entity without a predetermined content-length to use in a BodyParts.
|
||||
*/
|
||||
interface IndefiniteLength extends BodyPartEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* A part of a stream of incoming data for `Transfer-Encoding: chunked` messages.
|
||||
*/
|
||||
abstract class ChunkStreamPart {
|
||||
/**
|
||||
* Returns the byte data of this chunk. Will be non-empty for every regular
|
||||
* chunk. Will be empty for the last chunk.
|
||||
*/
|
||||
public abstract ByteString data();
|
||||
|
||||
/**
|
||||
* Returns extensions data for this chunk.
|
||||
*/
|
||||
public abstract String extension();
|
||||
|
||||
/**
|
||||
* Returns if this is the last chunk
|
||||
*/
|
||||
public abstract boolean isLastChunk();
|
||||
|
||||
/**
|
||||
* If this is the last chunk, this will return an Iterable of the trailer headers. Otherwise,
|
||||
* it will be empty.
|
||||
*/
|
||||
public abstract Iterable<HttpHeader> getTrailerHeaders();
|
||||
|
||||
/**
|
||||
* Creates a chunk from data and extension.
|
||||
*/
|
||||
public static ChunkStreamPart create(ByteString data, String extension) {
|
||||
return new akka.http.scaladsl.model.HttpEntity.Chunk(data, extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chunk from data with an empty extension.
|
||||
*/
|
||||
public static ChunkStreamPart create(ByteString data) {
|
||||
return create(data, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* The default last ChunkStreamPart that has no extension and no trailer headers.
|
||||
*/
|
||||
public static final ChunkStreamPart LAST = akka.http.scaladsl.model.HttpEntity.LastChunk$.MODULE$;
|
||||
|
||||
/**
|
||||
* Creates a last chunk with extension and headers.
|
||||
*/
|
||||
public static ChunkStreamPart createLast(String extension, Iterable<HttpHeader> trailerHeaders){
|
||||
return new akka.http.scaladsl.model.HttpEntity.LastChunk(extension, Util.<HttpHeader, akka.http.scaladsl.model.HttpHeader>convertIterable(trailerHeaders));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
import akka.stream.javadsl.Source;
|
||||
|
||||
/**
|
||||
* Represents an entity transferred using `Transfer-Encoding: chunked`. It consists of a
|
||||
* stream of {@link ChunkStreamPart}.
|
||||
*/
|
||||
public abstract class HttpEntityChunked implements RequestEntity, ResponseEntity {
|
||||
public abstract Source<ChunkStreamPart, ?> getChunks();
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
/**
|
||||
* Represents an entity without a predetermined content-length. Its length is implicitly
|
||||
* determined by closing the underlying connection. Therefore, this entity type is only
|
||||
* available for Http responses.
|
||||
*/
|
||||
public abstract class HttpEntityCloseDelimited implements ResponseEntity {}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
/**
|
||||
* The default entity type which has a predetermined length and a stream of data bytes.
|
||||
*/
|
||||
public abstract class HttpEntityDefault implements BodyPartEntity, RequestEntity, ResponseEntity {
|
||||
public abstract long contentLength();
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
/**
|
||||
* Represents an entity without a predetermined content-length to use in a BodyParts.
|
||||
*/
|
||||
public abstract class HttpEntityIndefiniteLength implements BodyPartEntity {}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model;
|
||||
|
||||
import akka.util.ByteString;
|
||||
|
||||
/**
|
||||
* The entity type which consists of a predefined fixed ByteString of data.
|
||||
*/
|
||||
public abstract class HttpEntityStrict implements BodyPartEntity, RequestEntity, ResponseEntity {
|
||||
public abstract ByteString data();
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ package akka.http.scaladsl.model
|
|||
import language.implicitConversions
|
||||
import java.io.File
|
||||
import java.lang.{ Iterable ⇒ JIterable, Long ⇒ JLong }
|
||||
import scala.util.control.NonFatal
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration._
|
||||
import scala.collection.immutable
|
||||
|
|
@ -15,14 +16,11 @@ import akka.stream.scaladsl._
|
|||
import akka.stream.stage._
|
||||
import akka.stream._
|
||||
import akka.{ japi, stream }
|
||||
import akka.http.javadsl.model.HttpEntityStrict
|
||||
import akka.http.scaladsl.model.ContentType.{ NonBinary, Binary }
|
||||
import akka.http.scaladsl.util.FastFuture
|
||||
import akka.http.javadsl.{ model ⇒ jm }
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
/**
|
||||
* Models the entity (aka "body" or "content) of an HTTP message.
|
||||
*/
|
||||
|
|
@ -100,7 +98,11 @@ sealed trait HttpEntity extends jm.HttpEntity {
|
|||
def withSizeLimit(maxBytes: Long): HttpEntity
|
||||
|
||||
/** Java API */
|
||||
def getDataBytes: stream.javadsl.Source[ByteString, AnyRef] = stream.javadsl.Source.fromGraph(dataBytes.asInstanceOf[Source[ByteString, AnyRef]])
|
||||
def getContentType: jm.ContentType = contentType
|
||||
|
||||
/** Java API */
|
||||
def getDataBytes: stream.javadsl.Source[ByteString, AnyRef] =
|
||||
stream.javadsl.Source.fromGraph(dataBytes.asInstanceOf[Source[ByteString, AnyRef]])
|
||||
|
||||
/** Java API */
|
||||
def getContentLengthOption: japi.Option[JLong] =
|
||||
|
|
@ -113,7 +115,7 @@ sealed trait HttpEntity extends jm.HttpEntity {
|
|||
def isChunked: Boolean = false
|
||||
|
||||
/** Java API */
|
||||
def toStrict(timeoutMillis: Long, materializer: Materializer): Future[HttpEntityStrict] =
|
||||
def toStrict(timeoutMillis: Long, materializer: Materializer): Future[jm.HttpEntity.Strict] =
|
||||
toStrict(timeoutMillis.millis)(materializer)
|
||||
}
|
||||
|
||||
|
|
@ -178,34 +180,41 @@ sealed trait UniversalEntity extends jm.UniversalEntity with MessageEntity with
|
|||
}
|
||||
|
||||
object HttpEntity {
|
||||
implicit def apply(string: String): Strict = apply(ContentTypes.`text/plain(UTF-8)`, string)
|
||||
implicit def apply(bytes: Array[Byte]): Strict = apply(ContentTypes.`application/octet-stream`, bytes)
|
||||
implicit def apply(data: ByteString): Strict = apply(ContentTypes.`application/octet-stream`, data)
|
||||
def apply(contentType: ContentType.NonBinary, string: String): Strict =
|
||||
implicit def apply(string: String): HttpEntity.Strict = apply(ContentTypes.`text/plain(UTF-8)`, string)
|
||||
implicit def apply(bytes: Array[Byte]): HttpEntity.Strict = apply(ContentTypes.`application/octet-stream`, bytes)
|
||||
implicit def apply(data: ByteString): HttpEntity.Strict = apply(ContentTypes.`application/octet-stream`, data)
|
||||
def apply(contentType: ContentType.NonBinary, string: String): HttpEntity.Strict =
|
||||
if (string.isEmpty) empty(contentType) else apply(contentType, ByteString(string.getBytes(contentType.charset.nioCharset)))
|
||||
def apply(contentType: ContentType, bytes: Array[Byte]): Strict =
|
||||
def apply(contentType: ContentType, bytes: Array[Byte]): HttpEntity.Strict =
|
||||
if (bytes.length == 0) empty(contentType) else apply(contentType, ByteString(bytes))
|
||||
def apply(contentType: ContentType, data: ByteString): Strict =
|
||||
if (data.isEmpty) empty(contentType) else Strict(contentType, data)
|
||||
def apply(contentType: ContentType, data: ByteString): HttpEntity.Strict =
|
||||
if (data.isEmpty) empty(contentType) else HttpEntity.Strict(contentType, data)
|
||||
|
||||
def apply(contentType: ContentType, contentLength: Long, data: Source[ByteString, Any]): UniversalEntity =
|
||||
if (contentLength == 0) empty(contentType) else Default(contentType, contentLength, data)
|
||||
def apply(contentType: ContentType, data: Source[ByteString, Any]): Chunked =
|
||||
Chunked.fromData(contentType, data)
|
||||
if (contentLength == 0) empty(contentType) else HttpEntity.Default(contentType, contentLength, data)
|
||||
def apply(contentType: ContentType, data: Source[ByteString, Any]): HttpEntity.Chunked =
|
||||
HttpEntity.Chunked.fromData(contentType, data)
|
||||
|
||||
/**
|
||||
* Returns either the empty entity, if the given file is empty, or a [[Default]] entity
|
||||
* consisting of a stream of [[ByteString]] instances each containing `chunkSize` bytes
|
||||
* (except for the final ByteString, which simply contains the remaining bytes).
|
||||
*
|
||||
* If the given `chunkSize` is -1 the default chunk size is used.
|
||||
*/
|
||||
def apply(contentType: ContentType, file: File, chunkSize: Int = -1): UniversalEntity = {
|
||||
val fileLength = file.length
|
||||
if (fileLength > 0)
|
||||
Default(contentType, fileLength,
|
||||
HttpEntity.Default(contentType, fileLength,
|
||||
if (chunkSize > 0) FileIO.fromFile(file, chunkSize) else FileIO.fromFile(file))
|
||||
else empty(contentType)
|
||||
}
|
||||
|
||||
val Empty: Strict = Strict(ContentTypes.NoContentType, data = ByteString.empty)
|
||||
val Empty: HttpEntity.Strict = HttpEntity.Strict(ContentTypes.NoContentType, data = ByteString.empty)
|
||||
|
||||
def empty(contentType: ContentType): Strict =
|
||||
def empty(contentType: ContentType): HttpEntity.Strict =
|
||||
if (contentType == Empty.contentType) Empty
|
||||
else Strict(contentType, data = ByteString.empty)
|
||||
else HttpEntity.Strict(contentType, data = ByteString.empty)
|
||||
|
||||
// TODO: re-establish serializability
|
||||
// TODO: equal/hashcode ?
|
||||
|
|
@ -214,7 +223,7 @@ object HttpEntity {
|
|||
* The model for the entity of a "regular" unchunked HTTP message with known, fixed data.
|
||||
*/
|
||||
final case class Strict(contentType: ContentType, data: ByteString)
|
||||
extends jm.HttpEntityStrict with UniversalEntity {
|
||||
extends jm.HttpEntity.Strict with UniversalEntity {
|
||||
|
||||
def contentLength: Long = data.length
|
||||
|
||||
|
|
@ -226,12 +235,12 @@ object HttpEntity {
|
|||
FastFuture.successful(this)
|
||||
|
||||
override def transformDataBytes(transformer: Flow[ByteString, ByteString, Any]): MessageEntity =
|
||||
Chunked.fromData(contentType, Source.single(data).via(transformer))
|
||||
HttpEntity.Chunked.fromData(contentType, Source.single(data).via(transformer))
|
||||
|
||||
override def transformDataBytes(newContentLength: Long, transformer: Flow[ByteString, ByteString, Any]): UniversalEntity =
|
||||
Default(contentType, newContentLength, Source.single(data) via transformer)
|
||||
HttpEntity.Default(contentType, newContentLength, Source.single(data) via transformer)
|
||||
|
||||
def withContentType(contentType: ContentType): Strict =
|
||||
def withContentType(contentType: ContentType): HttpEntity.Strict =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
||||
/**
|
||||
|
|
@ -239,7 +248,7 @@ object HttpEntity {
|
|||
*/
|
||||
def withSizeLimit(maxBytes: Long): UniversalEntity =
|
||||
if (data.length <= maxBytes) this
|
||||
else Default(contentType, data.length, limitableByteSource(Source.single(data))) withSizeLimit maxBytes
|
||||
else HttpEntity.Default(contentType, data.length, limitableByteSource(Source.single(data))) withSizeLimit maxBytes
|
||||
|
||||
override def productPrefix = "HttpEntity.Strict"
|
||||
|
||||
|
|
@ -263,6 +272,9 @@ object HttpEntity {
|
|||
|
||||
s"$productPrefix($contentType,$dataAsString)"
|
||||
}
|
||||
|
||||
/** Java API */
|
||||
override def getData = data
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -271,29 +283,32 @@ object HttpEntity {
|
|||
final case class Default(contentType: ContentType,
|
||||
contentLength: Long,
|
||||
data: Source[ByteString, Any])
|
||||
extends jm.HttpEntityDefault with UniversalEntity {
|
||||
extends jm.HttpEntity.Default with UniversalEntity {
|
||||
require(contentLength > 0, "contentLength must be positive (use `HttpEntity.empty(contentType)` for empty entities)")
|
||||
def isKnownEmpty = false
|
||||
override def isDefault: Boolean = true
|
||||
|
||||
def dataBytes: Source[ByteString, Any] = data
|
||||
|
||||
override def transformDataBytes(transformer: Flow[ByteString, ByteString, Any]): Chunked =
|
||||
Chunked.fromData(contentType, data via transformer)
|
||||
override def transformDataBytes(transformer: Flow[ByteString, ByteString, Any]): HttpEntity.Chunked =
|
||||
HttpEntity.Chunked.fromData(contentType, data via transformer)
|
||||
|
||||
override def transformDataBytes(newContentLength: Long, transformer: Flow[ByteString, ByteString, Any]): UniversalEntity =
|
||||
Default(contentType, newContentLength, data via transformer)
|
||||
HttpEntity.Default(contentType, newContentLength, data via transformer)
|
||||
|
||||
def withContentType(contentType: ContentType): Default =
|
||||
def withContentType(contentType: ContentType): HttpEntity.Default =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
||||
/**
|
||||
* See [[HttpEntity#withSizeLimit]].
|
||||
*/
|
||||
def withSizeLimit(maxBytes: Long): Default =
|
||||
def withSizeLimit(maxBytes: Long): HttpEntity.Default =
|
||||
copy(data = data withAttributes Attributes(SizeLimit(maxBytes, Some(contentLength))))
|
||||
|
||||
override def productPrefix = "HttpEntity.Default"
|
||||
|
||||
/** Java API */
|
||||
override def getContentLength = contentLength
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -302,7 +317,7 @@ object HttpEntity {
|
|||
* INTERNAL API
|
||||
*/
|
||||
private[http] sealed trait WithoutKnownLength extends HttpEntity {
|
||||
type Self <: WithoutKnownLength
|
||||
type Self <: HttpEntity.WithoutKnownLength
|
||||
def contentType: ContentType
|
||||
def data: Source[ByteString, Any]
|
||||
def contentLengthOption: Option[Long] = None
|
||||
|
|
@ -327,14 +342,14 @@ object HttpEntity {
|
|||
* Note that this type of HttpEntity can only be used for HttpResponses.
|
||||
*/
|
||||
final case class CloseDelimited(contentType: ContentType, data: Source[ByteString, Any])
|
||||
extends jm.HttpEntityCloseDelimited with ResponseEntity with WithoutKnownLength {
|
||||
type Self = CloseDelimited
|
||||
extends jm.HttpEntity.CloseDelimited with ResponseEntity with HttpEntity.WithoutKnownLength {
|
||||
type Self = HttpEntity.CloseDelimited
|
||||
|
||||
override def isCloseDelimited: Boolean = true
|
||||
def withContentType(contentType: ContentType): CloseDelimited =
|
||||
def withContentType(contentType: ContentType): HttpEntity.CloseDelimited =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
||||
def withData(data: Source[ByteString, Any]): CloseDelimited = copy(data = data)
|
||||
def withData(data: Source[ByteString, Any]): HttpEntity.CloseDelimited = copy(data = data)
|
||||
|
||||
override def productPrefix = "HttpEntity.CloseDelimited"
|
||||
}
|
||||
|
|
@ -344,14 +359,14 @@ object HttpEntity {
|
|||
* Note that this type of HttpEntity can only be used for BodyParts.
|
||||
*/
|
||||
final case class IndefiniteLength(contentType: ContentType, data: Source[ByteString, Any])
|
||||
extends jm.HttpEntityIndefiniteLength with BodyPartEntity with WithoutKnownLength {
|
||||
type Self = IndefiniteLength
|
||||
extends jm.HttpEntity.IndefiniteLength with BodyPartEntity with HttpEntity.WithoutKnownLength {
|
||||
type Self = HttpEntity.IndefiniteLength
|
||||
|
||||
override def isIndefiniteLength: Boolean = true
|
||||
def withContentType(contentType: ContentType): IndefiniteLength =
|
||||
def withContentType(contentType: ContentType): HttpEntity.IndefiniteLength =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
||||
def withData(data: Source[ByteString, Any]): IndefiniteLength = copy(data = data)
|
||||
def withData(data: Source[ByteString, Any]): HttpEntity.IndefiniteLength = copy(data = data)
|
||||
|
||||
override def productPrefix = "HttpEntity.IndefiniteLength"
|
||||
}
|
||||
|
|
@ -360,7 +375,7 @@ object HttpEntity {
|
|||
* The model for the entity of a chunked HTTP message (with `Transfer-Encoding: chunked`).
|
||||
*/
|
||||
final case class Chunked(contentType: ContentType, chunks: Source[ChunkStreamPart, Any])
|
||||
extends jm.HttpEntityChunked with MessageEntity {
|
||||
extends jm.HttpEntity.Chunked with MessageEntity {
|
||||
|
||||
def isKnownEmpty = chunks eq Source.empty
|
||||
def contentLengthOption: Option[Long] = None
|
||||
|
|
@ -369,10 +384,10 @@ object HttpEntity {
|
|||
|
||||
def dataBytes: Source[ByteString, Any] = chunks.map(_.data).filter(_.nonEmpty)
|
||||
|
||||
def withSizeLimit(maxBytes: Long): Chunked =
|
||||
def withSizeLimit(maxBytes: Long): HttpEntity.Chunked =
|
||||
copy(chunks = chunks withAttributes Attributes(SizeLimit(maxBytes)))
|
||||
|
||||
override def transformDataBytes(transformer: Flow[ByteString, ByteString, Any]): Chunked = {
|
||||
override def transformDataBytes(transformer: Flow[ByteString, ByteString, Any]): HttpEntity.Chunked = {
|
||||
val newData =
|
||||
chunks.map {
|
||||
case Chunk(data, "") ⇒ data
|
||||
|
|
@ -381,24 +396,25 @@ object HttpEntity {
|
|||
throw new IllegalArgumentException("Chunked.transformDataBytes not allowed for chunks with metadata")
|
||||
} via transformer
|
||||
|
||||
Chunked.fromData(contentType, newData)
|
||||
HttpEntity.Chunked.fromData(contentType, newData)
|
||||
}
|
||||
|
||||
def withContentType(contentType: ContentType): Chunked =
|
||||
def withContentType(contentType: ContentType): HttpEntity.Chunked =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
||||
override def productPrefix = "HttpEntity.Chunked"
|
||||
|
||||
/** Java API */
|
||||
def getChunks: stream.javadsl.Source[jm.ChunkStreamPart, Any] = stream.javadsl.Source.fromGraph(chunks)
|
||||
def getChunks: stream.javadsl.Source[jm.HttpEntity.ChunkStreamPart, AnyRef] =
|
||||
stream.javadsl.Source.fromGraph(chunks.asInstanceOf[Source[jm.HttpEntity.ChunkStreamPart, AnyRef]])
|
||||
}
|
||||
object Chunked {
|
||||
/**
|
||||
* Returns a ``Chunked`` entity where one Chunk is produced for every non-empty ByteString produced by the given
|
||||
* ``Source``.
|
||||
*/
|
||||
def fromData(contentType: ContentType, chunks: Source[ByteString, Any]): Chunked =
|
||||
Chunked(contentType, chunks.collect[ChunkStreamPart] {
|
||||
def fromData(contentType: ContentType, chunks: Source[ByteString, Any]): HttpEntity.Chunked =
|
||||
HttpEntity.Chunked(contentType, chunks.collect[ChunkStreamPart] {
|
||||
case b: ByteString if b.nonEmpty ⇒ Chunk(b)
|
||||
})
|
||||
}
|
||||
|
|
@ -407,7 +423,7 @@ object HttpEntity {
|
|||
* An element of the HttpEntity data stream.
|
||||
* Can be either a `Chunk` or a `LastChunk`.
|
||||
*/
|
||||
sealed abstract class ChunkStreamPart extends jm.ChunkStreamPart {
|
||||
sealed abstract class ChunkStreamPart extends jm.HttpEntity.ChunkStreamPart {
|
||||
def data: ByteString
|
||||
def extension: String
|
||||
def isLastChunk: Boolean
|
||||
|
|
@ -421,7 +437,7 @@ object HttpEntity {
|
|||
/**
|
||||
* An intermediate entity chunk guaranteed to carry non-empty data.
|
||||
*/
|
||||
final case class Chunk(data: ByteString, extension: String = "") extends ChunkStreamPart {
|
||||
final case class Chunk(data: ByteString, extension: String = "") extends HttpEntity.ChunkStreamPart {
|
||||
require(data.nonEmpty, "An HttpEntity.Chunk must have non-empty data")
|
||||
def isLastChunk = false
|
||||
|
||||
|
|
@ -438,7 +454,7 @@ object HttpEntity {
|
|||
* If you don't need extensions or trailer headers you can save an allocation
|
||||
* by directly using the `LastChunk` companion object.
|
||||
*/
|
||||
case class LastChunk(extension: String = "", trailer: immutable.Seq[HttpHeader] = Nil) extends ChunkStreamPart {
|
||||
case class LastChunk(extension: String = "", trailer: immutable.Seq[HttpHeader] = Nil) extends HttpEntity.ChunkStreamPart {
|
||||
def data = ByteString.empty
|
||||
def isLastChunk = true
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration
|
|||
/**
|
||||
* Returns the strictified entity of the response. It will be strictified on first access.
|
||||
*/
|
||||
lazy val entity: HttpEntityStrict = _response.entity.toStrict(awaitAtMost).awaitResult(awaitAtMost)
|
||||
lazy val entity: HttpEntity.Strict = _response.entity.toStrict(awaitAtMost).awaitResult(awaitAtMost)
|
||||
|
||||
/**
|
||||
* Returns a copy of the underlying response with the strictified entity.
|
||||
|
|
@ -47,7 +47,7 @@ abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration
|
|||
/**
|
||||
* Returns the bytes of the response entity
|
||||
*/
|
||||
def entityBytes: ByteString = entity.data()
|
||||
def entityBytes: ByteString = entity.getData
|
||||
|
||||
/**
|
||||
* Returns the entity of the response unmarshalled with the given ``Unmarshaller``.
|
||||
|
|
@ -60,7 +60,7 @@ abstract class TestResponse(_response: HttpResponse, awaitAtMost: FiniteDuration
|
|||
/**
|
||||
* Returns the entity of the response interpreted as an UTF-8 encoded string.
|
||||
*/
|
||||
def entityAsString: String = entity.data().utf8String
|
||||
def entityAsString: String = entity.getData.utf8String
|
||||
|
||||
/**
|
||||
* Returns the [[StatusCode]] of the response.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue