!htc #16826 introduce HttpCookiePair for usage in Cookie-header
This commit is contained in:
parent
43cca877fe
commit
b2e6b650fd
15 changed files with 115 additions and 59 deletions
|
|
@ -13,10 +13,10 @@ class CookieDirectivesExamplesSpec extends RoutingSpec {
|
|||
"cookie" in {
|
||||
val route =
|
||||
cookie("userName") { nameCookie =>
|
||||
complete(s"The logged in user is '${nameCookie.content}'")
|
||||
complete(s"The logged in user is '${nameCookie.value}'")
|
||||
}
|
||||
|
||||
Get("/") ~> Cookie(HttpCookie("userName", "paul")) ~> route ~> check {
|
||||
Get("/") ~> Cookie("userName" -> "paul") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The logged in user is 'paul'"
|
||||
}
|
||||
// missing cookie
|
||||
|
|
@ -30,11 +30,11 @@ class CookieDirectivesExamplesSpec extends RoutingSpec {
|
|||
"optionalCookie" in {
|
||||
val route =
|
||||
optionalCookie("userName") {
|
||||
case Some(nameCookie) => complete(s"The logged in user is '${nameCookie.content}'")
|
||||
case Some(nameCookie) => complete(s"The logged in user is '${nameCookie.value}'")
|
||||
case None => complete("No user logged in")
|
||||
}
|
||||
|
||||
Get("/") ~> Cookie(HttpCookie("userName", "paul")) ~> route ~> check {
|
||||
Get("/") ~> Cookie("userName" -> "paul") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The logged in user is 'paul'"
|
||||
}
|
||||
Get("/") ~> route ~> check {
|
||||
|
|
@ -49,18 +49,18 @@ class CookieDirectivesExamplesSpec extends RoutingSpec {
|
|||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The user was logged out"
|
||||
header[`Set-Cookie`] shouldEqual Some(`Set-Cookie`(HttpCookie("userName", content = "deleted", expires = Some(DateTime.MinValue))))
|
||||
header[`Set-Cookie`] shouldEqual Some(`Set-Cookie`(HttpCookie("userName", value = "deleted", expires = Some(DateTime.MinValue))))
|
||||
}
|
||||
}
|
||||
"setCookie" in {
|
||||
val route =
|
||||
setCookie(HttpCookie("userName", content = "paul")) {
|
||||
setCookie(HttpCookie("userName", value = "paul")) {
|
||||
complete("The user was logged in")
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The user was logged in"
|
||||
header[`Set-Cookie`] shouldEqual Some(`Set-Cookie`(HttpCookie("userName", content = "paul")))
|
||||
header[`Set-Cookie`] shouldEqual Some(`Set-Cookie`(HttpCookie("userName", value = "paul")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ package akka.http.javadsl.model.headers;
|
|||
* Specification: https://tools.ietf.org/html/rfc6265#section-4.2
|
||||
*/
|
||||
public abstract class Cookie extends akka.http.scaladsl.model.HttpHeader {
|
||||
public abstract Iterable<HttpCookie> getCookies();
|
||||
public abstract Iterable<HttpCookiePair> getCookies();
|
||||
|
||||
public static Cookie create(HttpCookie... cookies) {
|
||||
return new akka.http.scaladsl.model.headers.Cookie(akka.http.impl.util.Util.<HttpCookie, akka.http.scaladsl.model.headers.HttpCookie>convertArray(cookies));
|
||||
public static Cookie create(HttpCookiePair... cookies) {
|
||||
return new akka.http.scaladsl.model.headers.Cookie(akka.http.impl.util.Util.<HttpCookiePair, akka.http.scaladsl.model.headers.HttpCookiePair>convertArray(cookies));
|
||||
}
|
||||
public static Cookie create(String name, String value) {
|
||||
return create(HttpCookiePair.create(name, value));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import akka.japi.Option;
|
|||
|
||||
public abstract class HttpCookie {
|
||||
public abstract String name();
|
||||
public abstract String content();
|
||||
public abstract String value();
|
||||
public abstract HttpCookiePair pair();
|
||||
|
||||
public abstract Option<DateTime> getExpires();
|
||||
public abstract Option<Long> getMaxAge();
|
||||
|
|
@ -20,9 +21,9 @@ public abstract class HttpCookie {
|
|||
public abstract boolean httpOnly();
|
||||
public abstract Option<String> getExtension();
|
||||
|
||||
public static HttpCookie create(String name, String content) {
|
||||
public static HttpCookie create(String name, String value) {
|
||||
return new akka.http.scaladsl.model.headers.HttpCookie(
|
||||
name, content,
|
||||
name, value,
|
||||
Util.<akka.http.scaladsl.model.DateTime>scalaNone(), Util.scalaNone(), Util.<String>scalaNone(), Util.<String>scalaNone(),
|
||||
false, false,
|
||||
Util.<String>scalaNone());
|
||||
|
|
@ -30,7 +31,7 @@ public abstract class HttpCookie {
|
|||
@SuppressWarnings("unchecked")
|
||||
public static HttpCookie create(
|
||||
String name,
|
||||
String content,
|
||||
String value,
|
||||
Option<DateTime> expires,
|
||||
Option<Long> maxAge,
|
||||
Option<String> domain,
|
||||
|
|
@ -39,7 +40,7 @@ public abstract class HttpCookie {
|
|||
boolean httpOnly,
|
||||
Option<String> extension) {
|
||||
return new akka.http.scaladsl.model.headers.HttpCookie(
|
||||
name, content,
|
||||
name, value,
|
||||
Util.<DateTime, akka.http.scaladsl.model.DateTime>convertOptionToScala(expires),
|
||||
((Option<Object>) (Option) maxAge).asScala(),
|
||||
domain.asScala(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.model.headers;
|
||||
|
||||
/**
|
||||
* Represents a cookie pair as used in the `Cookie` header as specified in
|
||||
* http://tools.ietf.org/search/rfc6265#section-4.2.1
|
||||
*/
|
||||
public abstract class HttpCookiePair {
|
||||
public abstract String name();
|
||||
public abstract String value();
|
||||
|
||||
/**
|
||||
* Converts this cookie pair into an HttpCookie to be used with the
|
||||
* `Set-Cookie` header.
|
||||
*/
|
||||
public abstract HttpCookie toCookie();
|
||||
|
||||
public static HttpCookiePair create(String name, String value) {
|
||||
return new akka.http.scaladsl.model.headers.HttpCookiePair(name, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ private[parser] trait CommonRules { this: Parser with StringBuilding ⇒
|
|||
// https://tools.ietf.org/html/rfc6265#section-4.1.1
|
||||
// ******************************************************************************************
|
||||
def `cookie-pair` = rule {
|
||||
`cookie-name` ~ ws('=') ~ `cookie-value` ~> (HttpCookie(_, _))
|
||||
`cookie-name` ~ ws('=') ~ `cookie-value` ~> (HttpCookiePair(_: String, _: String))
|
||||
}
|
||||
|
||||
def `cookie-name` = rule { token }
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ private[parser] trait SimpleHeaders { this: Parser with CommonRules with CommonA
|
|||
|
||||
// https://tools.ietf.org/html/rfc6265
|
||||
def `set-cookie` = rule {
|
||||
`cookie-pair` ~ zeroOrMore(ws(';') ~ `cookie-av`) ~ EOI ~> (`Set-Cookie`(_))
|
||||
`cookie-pair` ~> (_.toCookie) ~ zeroOrMore(ws(';') ~ `cookie-av`) ~ EOI ~> (`Set-Cookie`(_))
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/rfc7230#section-6.7
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ private[http] class EnhancedString(val underlying: String) extends AnyVal {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns Some(String) if the underlying string is non-emtpy, None otherwise
|
||||
* Returns Some(String) if the underlying string is non-empty, None otherwise
|
||||
*/
|
||||
def toOption: Option[String] =
|
||||
if ((underlying eq null) || underlying.isEmpty) None else Some(underlying)
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ object JavaMapping {
|
|||
implicit object EntityTagRange extends Inherited[jm.headers.EntityTagRange, sm.headers.EntityTagRange]
|
||||
implicit object HttpChallenge extends Inherited[jm.headers.HttpChallenge, sm.headers.HttpChallenge]
|
||||
implicit object HttpCookie extends Inherited[jm.headers.HttpCookie, sm.headers.HttpCookie]
|
||||
implicit object HttpCookiePair extends Inherited[jm.headers.HttpCookiePair, sm.headers.HttpCookiePair]
|
||||
implicit object HttpCredentials extends Inherited[jm.headers.HttpCredentials, sm.headers.HttpCredentials]
|
||||
implicit object HttpEncoding extends Inherited[jm.headers.HttpEncoding, sm.headers.HttpEncoding]
|
||||
implicit object HttpEncodingRange extends Inherited[jm.headers.HttpEncodingRange, sm.headers.HttpEncodingRange]
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ final case class HttpRequest(method: HttpMethod = HttpMethods.GET,
|
|||
/**
|
||||
* All cookies provided by the client in one or more `Cookie` headers.
|
||||
*/
|
||||
def cookies: immutable.Seq[HttpCookie] = for (`Cookie`(cookies) ← headers; cookie ← cookies) yield cookie
|
||||
def cookies: immutable.Seq[HttpCookiePair] = for (`Cookie`(cookies) ← headers; cookie ← cookies) yield cookie
|
||||
|
||||
/**
|
||||
* Determines whether the given media-type is accepted by the client.
|
||||
|
|
|
|||
|
|
@ -11,29 +11,52 @@ import akka.http.impl.util._
|
|||
import akka.http.javadsl.{ model ⇒ jm }
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
|
||||
// see http://tools.ietf.org/html/rfc6265
|
||||
final case class HttpCookiePair(
|
||||
name: String,
|
||||
value: String) extends jm.headers.HttpCookiePair with ToStringRenderable {
|
||||
|
||||
HttpCookiePair.validate(name, value)
|
||||
|
||||
def render[R <: Rendering](r: R): r.type = r ~~ name ~~ '=' ~~ value
|
||||
def toCookie: HttpCookie = HttpCookie.fromPair(this)
|
||||
}
|
||||
object HttpCookiePair {
|
||||
def apply(pair: (String, String)): HttpCookiePair = HttpCookiePair(pair._1, pair._2)
|
||||
|
||||
private[http] def validate(name: String, value: String): Unit = {
|
||||
import HttpCookie._
|
||||
require(nameChars.matchesAll(name), s"'${nameChars.firstMismatch(name).get}' not allowed in cookie name ('$name')")
|
||||
require(valueChars.matchesAll(value), s"'${valueChars.firstMismatch(value).get}' not allowed in cookie content ('$value')")
|
||||
}
|
||||
}
|
||||
|
||||
// see http://tools.ietf.org/html/rfc6265
|
||||
final case class HttpCookie(
|
||||
name: String,
|
||||
content: String,
|
||||
value: String,
|
||||
expires: Option[DateTime] = None,
|
||||
maxAge: Option[Long] = None,
|
||||
domain: Option[String] = None,
|
||||
path: Option[String] = None,
|
||||
secure: Boolean = false,
|
||||
httpOnly: Boolean = false,
|
||||
extension: Option[String] = None) extends jm.headers.HttpCookie with ValueRenderable {
|
||||
extension: Option[String] = None) extends jm.headers.HttpCookie with ToStringRenderable {
|
||||
|
||||
/** Returns the name/value pair for this cookie, to be used in [[Cookiie]] headers. */
|
||||
def pair: HttpCookiePair = HttpCookiePair(name, value)
|
||||
|
||||
// TODO: suppress running these requires for cookies created from our header parser
|
||||
|
||||
import HttpCookie._
|
||||
|
||||
// TODO: suppress running these requires for cookies created from our header parser
|
||||
require(nameChars.matchesAll(name), s"'${nameChars.firstMismatch(name).get}' not allowed in cookie name ('$name')")
|
||||
require(contentChars.matchesAll(content), s"'${contentChars.firstMismatch(content).get}' not allowed in cookie content ('$content')")
|
||||
HttpCookiePair.validate(name, value)
|
||||
require(domain.forall(domainChars.matchesAll), s"'${domainChars.firstMismatch(domain.get).get}' not allowed in cookie domain ('${domain.get}')")
|
||||
require(path.forall(pathOrExtChars.matchesAll), s"'${pathOrExtChars.firstMismatch(path.get).get}' not allowed in cookie path ('${path.get}')")
|
||||
require(extension.forall(pathOrExtChars.matchesAll), s"'${pathOrExtChars.firstMismatch(extension.get).get}' not allowed in cookie extension ('${extension.get}')")
|
||||
|
||||
def render[R <: Rendering](r: R): r.type = {
|
||||
r ~~ name ~~ '=' ~~ content
|
||||
r ~~ name ~~ '=' ~~ value
|
||||
if (expires.isDefined) expires.get.renderRfc1123DateTimeString(r ~~ "; Expires=")
|
||||
if (maxAge.isDefined) r ~~ "; Max-Age=" ~~ maxAge.get
|
||||
if (domain.isDefined) r ~~ "; Domain=" ~~ domain.get
|
||||
|
|
@ -57,12 +80,22 @@ final case class HttpCookie(
|
|||
}
|
||||
|
||||
object HttpCookie {
|
||||
def fromPair(pair: HttpCookiePair,
|
||||
expires: Option[DateTime] = None,
|
||||
maxAge: Option[Long] = None,
|
||||
domain: Option[String] = None,
|
||||
path: Option[String] = None,
|
||||
secure: Boolean = false,
|
||||
httpOnly: Boolean = false,
|
||||
extension: Option[String] = None): HttpCookie =
|
||||
HttpCookie(pair.name, pair.value, expires, maxAge, domain, path, secure, httpOnly, extension)
|
||||
|
||||
import akka.http.impl.model.parser.CharacterClasses._
|
||||
|
||||
def nameChars = tchar
|
||||
private[http] def nameChars = tchar
|
||||
// http://tools.ietf.org/html/rfc6265#section-4.1.1
|
||||
// ; US-ASCII characters excluding CTLs, whitespace DQUOTE, comma, semicolon, and backslash
|
||||
val contentChars = CharPredicate('\u0021', '\u0023' to '\u002B', '\u002D' to '\u003A', '\u003C' to '\u005B', '\u005D' to '\u007E')
|
||||
val domainChars = ALPHANUM ++ ".-"
|
||||
val pathOrExtChars = VCHAR ++ ' ' -- ';'
|
||||
private[http] val valueChars = CharPredicate('\u0021', '\u0023' to '\u002B', '\u002D' to '\u003A', '\u003C' to '\u005B', '\u005D' to '\u007E')
|
||||
private[http] val domainChars = ALPHANUM ++ ".-"
|
||||
private[http] val pathOrExtChars = VCHAR ++ ' ' -- ';'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,20 +384,19 @@ final case class `Content-Type` private[http] (contentType: ContentType) extends
|
|||
|
||||
// https://tools.ietf.org/html/rfc6265#section-4.2
|
||||
object Cookie extends ModeledCompanion {
|
||||
implicit val cookieNameValueOnlyRenderer: Renderer[HttpCookie] = new Renderer[HttpCookie] {
|
||||
def render[R <: Rendering](r: R, c: HttpCookie): r.type = r ~~ c.name ~~ '=' ~~ c.content
|
||||
}
|
||||
def apply(first: HttpCookie, more: HttpCookie*): Cookie = apply(immutable.Seq(first +: more: _*))
|
||||
implicit val cookiesRenderer = Renderer.seqRenderer[HttpCookie](separator = "; ") // cache
|
||||
def apply(first: HttpCookiePair, more: HttpCookiePair*): Cookie = apply(immutable.Seq(first +: more: _*))
|
||||
def apply(name: String, value: String): Cookie = apply(HttpCookiePair(name, value))
|
||||
def apply(values: (String, String)*): Cookie = apply(values.map(HttpCookiePair(_)).toList)
|
||||
implicit val cookiePairsRenderer = Renderer.seqRenderer[HttpCookiePair](separator = "; ") // cache
|
||||
}
|
||||
final case class Cookie(cookies: immutable.Seq[HttpCookie]) extends jm.headers.Cookie with ModeledHeader {
|
||||
final case class Cookie(cookies: immutable.Seq[HttpCookiePair]) extends jm.headers.Cookie with ModeledHeader {
|
||||
require(cookies.nonEmpty, "cookies must not be empty")
|
||||
import Cookie.cookiesRenderer
|
||||
import Cookie.cookiePairsRenderer
|
||||
def renderValue[R <: Rendering](r: R): r.type = r ~~ cookies
|
||||
protected def companion = Cookie
|
||||
|
||||
/** Java API */
|
||||
def getCookies: Iterable[jm.headers.HttpCookie] = cookies.asJava
|
||||
def getCookies: Iterable[jm.headers.HttpCookiePair] = cookies.asJava
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/rfc7231#section-7.1.1.2
|
||||
|
|
|
|||
|
|
@ -217,19 +217,12 @@ class HttpHeaderSpec extends FreeSpec with Matchers {
|
|||
}
|
||||
|
||||
"Cookie" in {
|
||||
"Cookie: SID=31d4d96e407aad42" =!= Cookie(HttpCookie("SID", "31d4d96e407aad42"))
|
||||
"Cookie: SID=31d4d96e407aad42; lang=en>US" =!= Cookie(HttpCookie("SID", "31d4d96e407aad42"), HttpCookie("lang", "en>US"))
|
||||
"Cookie: a=1;b=2" =!= Cookie(HttpCookie("a", "1"), HttpCookie("b", "2")).renderedTo("a=1; b=2")
|
||||
"Cookie: a=1 ;b=2" =!= Cookie(HttpCookie("a", "1"), HttpCookie("b", "2")).renderedTo("a=1; b=2")
|
||||
"Cookie: a=1; b=2" =!= Cookie(HttpCookie("a", "1"), HttpCookie("b", "2"))
|
||||
"Cookie: a=1,b=2" =!= Cookie(HttpCookie("a", "1"), HttpCookie("b", "2")).renderedTo("a=1; b=2")
|
||||
Cookie(HttpCookie("SID", "31d4d96e407aad42",
|
||||
domain = Some("example.com"),
|
||||
expires = Some(DateTime(2021, 6, 9, 10, 18, 14)),
|
||||
path = Some("/hello"),
|
||||
httpOnly = true,
|
||||
extension = Some("fancyPants"),
|
||||
secure = true)).toString shouldEqual "Cookie: SID=31d4d96e407aad42"
|
||||
"Cookie: SID=31d4d96e407aad42" =!= Cookie("SID" -> "31d4d96e407aad42")
|
||||
"Cookie: SID=31d4d96e407aad42; lang=en>US" =!= Cookie("SID" -> "31d4d96e407aad42", "lang" -> "en>US")
|
||||
"Cookie: a=1;b=2" =!= Cookie("a" -> "1", "b" -> "2").renderedTo("a=1; b=2")
|
||||
"Cookie: a=1 ;b=2" =!= Cookie("a" -> "1", "b" -> "2").renderedTo("a=1; b=2")
|
||||
"Cookie: a=1; b=2" =!= Cookie("a" -> "1", "b" -> "2")
|
||||
"Cookie: a=1,b=2" =!= Cookie("a" -> "1", "b" -> "2").renderedTo("a=1; b=2")
|
||||
}
|
||||
|
||||
"Date" in {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package akka.http.javadsl.model
|
||||
|
||||
import akka.http.javadsl.model.headers.Cookie
|
||||
|
||||
import scala.collection.immutable
|
||||
import org.scalatest.{ MustMatchers, FreeSpec }
|
||||
import akka.http.scaladsl.model.headers.BasicHttpCredentials
|
||||
|
|
@ -42,7 +44,7 @@ class JavaApiTestCaseSpecs extends FreeSpec with MustMatchers {
|
|||
model.HttpRequest(headers = immutable.Seq(model.headers.Authorization(BasicHttpCredentials("username", "password")))))
|
||||
}
|
||||
"removeCookies" in {
|
||||
val testRequest = model.HttpRequest(headers = immutable.Seq(model.headers.Cookie(model.headers.HttpCookie("test", "blub"))))
|
||||
val testRequest = model.HttpRequest(headers = immutable.Seq(Cookie.create("test", "blub")))
|
||||
JavaApiTestCases.removeCookies(testRequest) must be(
|
||||
model.HttpRequest())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class CookieDirectivesSpec extends RoutingSpec {
|
|||
|
||||
"The 'cookie' directive" should {
|
||||
"extract the respectively named cookie" in {
|
||||
Get() ~> addHeader(Cookie(HttpCookie("fancy", "pants"))) ~> {
|
||||
Get() ~> addHeader(Cookie("fancy" -> "pants")) ~> {
|
||||
cookie("fancy") { echoComplete }
|
||||
} ~> check { responseAs[String] shouldEqual "fancy=pants" }
|
||||
}
|
||||
|
|
@ -25,8 +25,8 @@ class CookieDirectivesSpec extends RoutingSpec {
|
|||
} ~> check { rejection shouldEqual MissingCookieRejection("fancy") }
|
||||
}
|
||||
"properly pass through inner rejections" in {
|
||||
Get() ~> addHeader(Cookie(HttpCookie("fancy", "pants"))) ~> {
|
||||
cookie("fancy") { c ⇒ reject(ValidationRejection("Dont like " + c.content)) }
|
||||
Get() ~> addHeader(Cookie("fancy" -> "pants")) ~> {
|
||||
cookie("fancy") { c ⇒ reject(ValidationRejection("Dont like " + c.value)) }
|
||||
} ~> check { rejection shouldEqual ValidationRejection("Dont like pants") }
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ class CookieDirectivesSpec extends RoutingSpec {
|
|||
|
||||
"The 'optionalCookie' directive" should {
|
||||
"produce a `Some(cookie)` extraction if the cookie is present" in {
|
||||
Get() ~> Cookie(HttpCookie("abc", "123")) ~> {
|
||||
Get() ~> Cookie("abc" -> "123") ~> {
|
||||
optionalCookie("abc") { echoComplete }
|
||||
} ~> check { responseAs[String] shouldEqual "Some(abc=123)" }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,17 +18,17 @@ trait CookieDirectives {
|
|||
* Extracts an HttpCookie with the given name. If the cookie is not present the
|
||||
* request is rejected with a respective [[MissingCookieRejection]].
|
||||
*/
|
||||
def cookie(name: String): Directive1[HttpCookie] =
|
||||
def cookie(name: String): Directive1[HttpCookiePair] =
|
||||
headerValue(findCookie(name)) | reject(MissingCookieRejection(name))
|
||||
|
||||
/**
|
||||
* Extracts an HttpCookie with the given name.
|
||||
* If the cookie is not present a value of `None` is extracted.
|
||||
*/
|
||||
def optionalCookie(name: String): Directive1[Option[HttpCookie]] =
|
||||
def optionalCookie(name: String): Directive1[Option[HttpCookiePair]] =
|
||||
optionalHeaderValue(findCookie(name))
|
||||
|
||||
private def findCookie(name: String): HttpHeader ⇒ Option[HttpCookie] = {
|
||||
private def findCookie(name: String): HttpHeader ⇒ Option[HttpCookiePair] = {
|
||||
case Cookie(cookies) ⇒ cookies.find(_.name == name)
|
||||
case _ ⇒ None
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ trait CookieDirectives {
|
|||
*/
|
||||
def deleteCookie(first: HttpCookie, more: HttpCookie*): Directive0 =
|
||||
respondWithHeaders((first :: more.toList).map { c ⇒
|
||||
`Set-Cookie`(c.copy(content = "deleted", expires = Some(DateTime.MinValue)))
|
||||
`Set-Cookie`(c.copy(value = "deleted", expires = Some(DateTime.MinValue)))
|
||||
})
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue