Skip to content
This repository has been archived by the owner on Apr 24, 2024. It is now read-only.

Commit

Permalink
+ routing: upgrade autoChunk directive, add autoChunkFileBytes di…
Browse files Browse the repository at this point in the history
…rective
  • Loading branch information
sirthias committed Sep 10, 2013
1 parent cf5340d commit fcc83fc
Showing 1 changed file with 39 additions and 20 deletions.
Expand Up @@ -18,41 +18,60 @@ package spray.routing
package directives

import akka.actor.ActorRefFactory
import spray.http.{ HttpEntity, HttpResponse }
import spray.http.{ HttpData, HttpEntity, HttpResponse }
import spray.httpx.marshalling.BasicMarshallers
import akka.util.ByteString

trait ChunkingDirectives {
import BasicDirectives._

/**
* Automatically converts non-rejected responses from its inner route into chunked responses of which each chunk
* (save the very last) has the given size.
* If the response content from the inner route is smaller than chunkSize a "regular", unchunked response is produced.
* Converts unchunked HttpResponses coming back from its inner route into chunked responses of which each chunk
* is smaller or equal to the given size, if the response entity is at least as large as the given threshold.
* If the response content from the inner route is smaller than the given threshold the response is left untouched.
*/
def autoChunk(csm: ChunkSizeMagnet) = mapRequestContext { ctx
def autoChunk(csm: ChunkSizeMagnet): Directive0 = mapRequestContext { ctx
import csm._
ctx.withRouteResponseHandling {
case HttpResponse(_, HttpEntity.NonEmpty(contentType, data), _, _) if data.length > chunkSize
def split(ix: Long = 0L): Stream[Array[Byte]] = {
def chunkBuf(size: Int) = {
val array = new Array[Byte](size)
data.copyToArray(array, sourceOffset = ix, span = size)
array
}
if (ix < data.length - chunkSize) Stream.cons(chunkBuf(chunkSize), split(ix + chunkSize))
else Stream.cons(chunkBuf((data.length - ix).toInt), Stream.Empty)
}
implicit val marshaller = BasicMarshallers.byteArrayMarshaller(contentType)
ctx.complete(split())
case HttpResponse(_, HttpEntity.NonEmpty(contentType, data), _, _) if csm selects data
implicit val marshaller = BasicMarshallers.byteStringMarshaller(contentType)
ctx.complete(chunkStream(data))
}
}

/**
* Converts unchunked HttpResponses coming back from its inner route into chunked responses of which each chunk
* is smaller or equal to the given size, if the response entity contains HttpData.FileBytes and is at least as
* large as the given threshold.
* If the response content from the inner route is smaller than the given threshold the response is left untouched.
*/
def autoChunkFileBytes(csm: ChunkSizeMagnet): Directive0 =
autoChunk {
new ChunkSizeMagnet {
implicit def refFactory: ActorRefFactory = csm.refFactory
def selects(data: HttpData): Boolean = data.hasFileBytes && csm.selects(data)
def chunkStream(data: HttpData): Stream[ByteString] = csm.chunkStream(data)
}
}
}

object ChunkingDirectives extends ChunkingDirectives

class ChunkSizeMagnet(val chunkSize: Int)(implicit val refFactory: ActorRefFactory)
abstract class ChunkSizeMagnet {
implicit def refFactory: ActorRefFactory
def selects(data: HttpData): Boolean
def chunkStream(data: HttpData): Stream[ByteString]
}

object ChunkSizeMagnet {
implicit def fromInt(chunkSize: Int)(implicit factory: ActorRefFactory) =
new ChunkSizeMagnet(chunkSize)
class Default(thresholdSize: Long, maxChunkSize: Int)(implicit val refFactory: ActorRefFactory) extends ChunkSizeMagnet {
def selects(data: HttpData): Boolean = thresholdSize > 0 && data.length > thresholdSize
def chunkStream(data: HttpData): Stream[ByteString] = data.toChunkStream(maxChunkSize)
}
implicit def fromInt(maxChunkSize: Int)(implicit factory: ActorRefFactory): ChunkSizeMagnet =
new Default(maxChunkSize, maxChunkSize)
implicit def fromLongAndInt(pair: (Long, Int))(implicit factory: ActorRefFactory): ChunkSizeMagnet =
new Default(pair._1, pair._2)
implicit def fromIntAndInt(pair: (Int, Int))(implicit factory: ActorRefFactory): ChunkSizeMagnet =
new Default(pair._1, pair._2)
}

0 comments on commit fcc83fc

Please sign in to comment.