in http/src/main/scala/org/apache/pekko/http/scaladsl/server/directives/CacheConditionDirectives.scala [46:151]
def conditional(eTag: EntityTag): Directive0 = conditional(Some(eTag), None)
/**
* Wraps its inner route with support for Conditional Requests as defined
* by http://tools.ietf.org/html/rfc7232
*
* In particular the algorithm defined by http://tools.ietf.org/html/rfc7232#section-6
* is implemented by this directive.
*
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
* must be on a deeper level in your route structure in order to function correctly.
*
* @group cachecondition
*/
def conditional(lastModified: DateTime): Directive0 = conditional(None, Some(lastModified))
/**
* Wraps its inner route with support for Conditional Requests as defined
* by http://tools.ietf.org/html/rfc7232
*
* In particular the algorithm defined by http://tools.ietf.org/html/rfc7232#section-6
* is implemented by this directive.
*
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
* must be on a deeper level in your route structure in order to function correctly.
*
* @group cachecondition
*/
def conditional(eTag: EntityTag, lastModified: DateTime): Directive0 = conditional(Some(eTag), Some(lastModified))
/**
* Wraps its inner route with support for Conditional Requests as defined
* by http://tools.ietf.org/html/rfc7232
*
* In particular the algorithm defined by http://tools.ietf.org/html/rfc7232#section-6
* is implemented by this directive.
*
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
* must be on a deeper level in your route structure in order to function correctly.
*
* @group cachecondition
*/
def conditional(eTag: Option[EntityTag], lastModified: Option[DateTime]): Directive0 = {
def addResponseHeaders: Directive0 =
mapResponse(_.withDefaultHeaders(eTag.map(ETag(_)).toList ++ lastModified.map(`Last-Modified`(_)).toList))
// TODO: also handle Cache-Control and Vary
def complete304(): Route = addResponseHeaders(complete(HttpResponse(NotModified)))
def complete412(): Route = _.complete(PreconditionFailed)
extractRequest.flatMap { request =>
import request._
mapInnerRoute { route =>
def innerRouteWithRangeHeaderFilteredOut: Route =
(mapRequest(_.mapHeaders(_.filterNot(_.isInstanceOf[Range]))) &
addResponseHeaders)(route)
def isGetOrHead = method == HEAD || method == GET
def unmodified(ifModifiedSince: DateTime) =
lastModified.get <= ifModifiedSince && ifModifiedSince.clicks < System.currentTimeMillis()
def step1(): Route =
header[`If-Match`] match {
case Some(`If-Match`(im)) if eTag.isDefined =>
if (matchesRange(eTag.get, im, weakComparison = false)) step3() else complete412()
case _ => step2()
}
def step2(): Route =
header[`If-Unmodified-Since`] match {
case Some(`If-Unmodified-Since`(ius)) if lastModified.isDefined && !unmodified(ius) => complete412()
case _ => step3()
}
def step3(): Route =
header[`If-None-Match`] match {
case Some(`If-None-Match`(inm)) if eTag.isDefined =>
if (!matchesRange(eTag.get, inm, weakComparison = true)) step5()
else if (isGetOrHead) complete304()
else complete412()
case _ => step4()
}
def step4(): Route =
if (isGetOrHead) {
header[`If-Modified-Since`] match {
case Some(`If-Modified-Since`(ims)) if lastModified.isDefined && unmodified(ims) => complete304()
case _ => step5()
}
} else step5()
def step5(): Route =
if (method == GET && header[Range].isDefined)
header[`If-Range`] match {
case Some(`If-Range`(Left(tag))) if eTag.isDefined && !matches(eTag.get, tag, weakComparison = false) =>
innerRouteWithRangeHeaderFilteredOut
case Some(`If-Range`(Right(ims))) if lastModified.isDefined && !unmodified(ims) =>
innerRouteWithRangeHeaderFilteredOut
case _ => step6()
}
else step6()
def step6(): Route = addResponseHeaders(route)
step1()
}
}
}