Merge pull request #16195 from spray/w/15930-RangeDirectives
+htp #15930 import RangeDirectives from spray
This commit is contained in:
commit
04385f4d91
8 changed files with 341 additions and 6 deletions
|
|
@ -106,6 +106,13 @@ sealed trait ResponseEntity extends HttpEntity with japi.ResponseEntity {
|
|||
/* An entity that can be used for requests, responses, and body parts */
|
||||
sealed trait UniversalEntity extends japi.UniversalEntity with MessageEntity with BodyPartEntity {
|
||||
def withContentType(contentType: ContentType): UniversalEntity
|
||||
def contentLength: Long
|
||||
|
||||
/**
|
||||
* Transforms this' entities data bytes with a transformer that will produce exactly the number of bytes given as
|
||||
* ``newContentLength``.
|
||||
*/
|
||||
def transformDataBytes(newContentLength: Long, transformer: () ⇒ Transformer[ByteString, ByteString]): UniversalEntity
|
||||
}
|
||||
|
||||
object HttpEntity {
|
||||
|
|
@ -141,6 +148,7 @@ object HttpEntity {
|
|||
*/
|
||||
final case class Strict(contentType: ContentType, data: ByteString)
|
||||
extends japi.HttpEntityStrict with UniversalEntity {
|
||||
def contentLength: Long = data.length
|
||||
|
||||
def isKnownEmpty: Boolean = data.isEmpty
|
||||
|
||||
|
|
@ -159,6 +167,12 @@ object HttpEntity {
|
|||
Chunked(contentType, Source.failed(ex))
|
||||
}
|
||||
}
|
||||
override def transformDataBytes(newContentLength: Long, transformer: () ⇒ Transformer[ByteString, ByteString]): UniversalEntity = {
|
||||
val t = transformer()
|
||||
val newData = (t.onNext(data) ++ t.onTermination(None)).join
|
||||
assert(newData.length.toLong == newContentLength, s"Transformer didn't produce as much bytes (${newData.length}:'${newData.utf8String}') as claimed ($newContentLength)")
|
||||
copy(data = newData)
|
||||
}
|
||||
|
||||
def withContentType(contentType: ContentType): Strict =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
|
@ -185,6 +199,8 @@ object HttpEntity {
|
|||
|
||||
HttpEntity.Chunked(contentType, chunks)
|
||||
}
|
||||
override def transformDataBytes(newContentLength: Long, transformer: () ⇒ Transformer[ByteString, ByteString]): UniversalEntity =
|
||||
Default(contentType, newContentLength, data.transform("transformDataBytes-with-new-length-Default", transformer))
|
||||
|
||||
def withContentType(contentType: ContentType): Default =
|
||||
if (contentType == this.contentType) this else copy(contentType = contentType)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,46 @@ private[http] object StreamUtils {
|
|||
override def onError(cause: scala.Throwable): Unit = throw f(cause)
|
||||
}
|
||||
|
||||
def sliceBytesTransformer(start: Long, length: Long): Transformer[ByteString, ByteString] =
|
||||
new Transformer[ByteString, ByteString] {
|
||||
type State = Transformer[ByteString, ByteString]
|
||||
|
||||
def skipping = new State {
|
||||
var toSkip = start
|
||||
def onNext(element: ByteString): immutable.Seq[ByteString] =
|
||||
if (element.length < toSkip) {
|
||||
// keep skipping
|
||||
toSkip -= element.length
|
||||
Nil
|
||||
} else {
|
||||
become(taking(length))
|
||||
// toSkip <= element.length <= Int.MaxValue
|
||||
currentState.onNext(element.drop(toSkip.toInt))
|
||||
}
|
||||
}
|
||||
def taking(initiallyRemaining: Long) = new State {
|
||||
var remaining: Long = initiallyRemaining
|
||||
def onNext(element: ByteString): immutable.Seq[ByteString] = {
|
||||
val data = element.take(math.min(remaining, Int.MaxValue).toInt)
|
||||
remaining -= data.size
|
||||
if (remaining <= 0) become(finishing)
|
||||
data :: Nil
|
||||
}
|
||||
}
|
||||
def finishing = new State {
|
||||
override def isComplete: Boolean = true
|
||||
def onNext(element: ByteString): immutable.Seq[ByteString] =
|
||||
throw new IllegalStateException("onNext called on complete stream")
|
||||
}
|
||||
|
||||
var currentState: State = if (start > 0) skipping else taking(length)
|
||||
def become(state: State): Unit = currentState = state
|
||||
|
||||
override def isComplete: Boolean = currentState.isComplete
|
||||
def onNext(element: ByteString): immutable.Seq[ByteString] = currentState.onNext(element)
|
||||
override def onTermination(e: Option[Throwable]): immutable.Seq[ByteString] = currentState.onTermination(e)
|
||||
}
|
||||
|
||||
def mapEntityError(f: Throwable ⇒ Throwable): RequestEntity ⇒ RequestEntity =
|
||||
_.transformDataBytes(() ⇒ mapErrorTransformer(f))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@ import language.implicitConversions
|
|||
import language.higherKinds
|
||||
import java.nio.charset.Charset
|
||||
import com.typesafe.config.Config
|
||||
import akka.stream.FlattenStrategy
|
||||
import akka.stream.{ FlowMaterializer, FlattenStrategy, Transformer }
|
||||
import akka.stream.scaladsl.{ Flow, Source }
|
||||
import scala.concurrent.Future
|
||||
import scala.util.matching.Regex
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.util.ByteString
|
||||
import akka.actor._
|
||||
import akka.stream.Transformer
|
||||
import scala.collection.immutable
|
||||
|
||||
package object util {
|
||||
private[http] val UTF8 = Charset.forName("UTF8")
|
||||
|
|
@ -53,7 +54,7 @@ package object util {
|
|||
.flatten(FlattenStrategy.concat)
|
||||
}
|
||||
|
||||
private[http] implicit class SourceWithPrintEvent[T](val underlying: Source[T]) {
|
||||
private[http] implicit class EnhancedSource[T](val underlying: Source[T]) {
|
||||
def printEvent(marker: String): Source[T] =
|
||||
underlying.transform("transform",
|
||||
() ⇒ new Transformer[T, T] {
|
||||
|
|
@ -66,6 +67,14 @@ package object util {
|
|||
Nil
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Drain this stream into a Vector and provide it as a future value.
|
||||
*
|
||||
* FIXME: Should be part of akka-streams
|
||||
*/
|
||||
def collectAll(implicit materializer: FlowMaterializer): Future[immutable.Seq[T]] =
|
||||
underlying.fold(Vector.empty[T])(_ :+ _)
|
||||
}
|
||||
|
||||
private[http] def errorLogger(log: LoggingAdapter, msg: String): Transformer[ByteString, ByteString] =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue