Merge pull request #17767 from spray/w/various-small-improvements
Various small improvements
This commit is contained in:
commit
e70b8c3e48
6 changed files with 109 additions and 24 deletions
|
|
@ -28,6 +28,14 @@ public abstract class HttpCookie {
|
||||||
false, false,
|
false, false,
|
||||||
Util.<String>scalaNone());
|
Util.<String>scalaNone());
|
||||||
}
|
}
|
||||||
|
public static HttpCookie create(String name, String value, Option<String> domain, Option<String> path) {
|
||||||
|
return new akka.http.scaladsl.model.headers.HttpCookie(
|
||||||
|
name, value,
|
||||||
|
Util.<akka.http.scaladsl.model.DateTime>scalaNone(), Util.scalaNone(),
|
||||||
|
domain.asScala(), path.asScala(),
|
||||||
|
false, false,
|
||||||
|
Util.<String>scalaNone());
|
||||||
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static HttpCookie create(
|
public static HttpCookie create(
|
||||||
String name,
|
String name,
|
||||||
|
|
@ -49,4 +57,39 @@ public abstract class HttpCookie {
|
||||||
httpOnly,
|
httpOnly,
|
||||||
extension.asScala());
|
extension.asScala());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given expiration set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withExpires(DateTime dateTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given max age set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withMaxAge(long maxAge);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given domain set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withDomain(String domain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given path set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withPath(String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given secure flag set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withSecure(boolean secure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given http-only flag set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withHttpOnly(boolean httpOnly);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this HttpCookie instance with the given extension set.
|
||||||
|
*/
|
||||||
|
public abstract HttpCookie withExtension(String extension);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,8 @@ package akka.http.javadsl.model.headers;
|
||||||
public abstract class RawHeader extends akka.http.scaladsl.model.HttpHeader {
|
public abstract class RawHeader extends akka.http.scaladsl.model.HttpHeader {
|
||||||
public abstract String name();
|
public abstract String name();
|
||||||
public abstract String value();
|
public abstract String value();
|
||||||
|
|
||||||
|
public static RawHeader create(String name, String value) {
|
||||||
|
return new akka.http.scaladsl.model.headers.RawHeader(name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package akka.http.scaladsl.model.headers
|
package akka.http.scaladsl.model.headers
|
||||||
|
|
||||||
|
import akka.http.javadsl.model.headers
|
||||||
import akka.parboiled2.CharPredicate
|
import akka.parboiled2.CharPredicate
|
||||||
import akka.japi.{ Option ⇒ JOption }
|
import akka.japi.{ Option ⇒ JOption }
|
||||||
import akka.http.scaladsl.model.DateTime
|
import akka.http.scaladsl.model.DateTime
|
||||||
|
|
@ -77,6 +78,20 @@ final case class HttpCookie(
|
||||||
def getMaxAge: JOption[java.lang.Long] = maxAge.asJava
|
def getMaxAge: JOption[java.lang.Long] = maxAge.asJava
|
||||||
/** Java API */
|
/** Java API */
|
||||||
def getExpires: JOption[jm.DateTime] = expires.asJava
|
def getExpires: JOption[jm.DateTime] = expires.asJava
|
||||||
|
/** Java API */
|
||||||
|
def withExpires(dateTime: jm.DateTime): headers.HttpCookie = copy(expires = Some(dateTime.asScala))
|
||||||
|
/** Java API */
|
||||||
|
def withDomain(domain: String): headers.HttpCookie = copy(domain = Some(domain))
|
||||||
|
/** Java API */
|
||||||
|
def withPath(path: String): headers.HttpCookie = copy(path = Some(path))
|
||||||
|
/** Java API */
|
||||||
|
def withMaxAge(maxAge: Long): headers.HttpCookie = copy(maxAge = Some(maxAge))
|
||||||
|
/** Java API */
|
||||||
|
def withSecure(secure: Boolean): headers.HttpCookie = copy(secure = secure)
|
||||||
|
/** Java API */
|
||||||
|
def withHttpOnly(httpOnly: Boolean): headers.HttpCookie = copy(httpOnly = httpOnly)
|
||||||
|
/** Java API */
|
||||||
|
def withExtension(extension: String): headers.HttpCookie = copy(extension = Some(extension))
|
||||||
}
|
}
|
||||||
|
|
||||||
object HttpCookie {
|
object HttpCookie {
|
||||||
|
|
|
||||||
|
|
@ -53,16 +53,16 @@ class PathDirectivesSpec extends RoutingSpec with Inside {
|
||||||
val test = testFor(pathPrefix("ab[cd]+".r) { echoCaptureAndUnmatchedPath })
|
val test = testFor(pathPrefix("ab[cd]+".r) { echoCaptureAndUnmatchedPath })
|
||||||
"reject [/bar]" in test()
|
"reject [/bar]" in test()
|
||||||
"reject [/ab/cd]" in test()
|
"reject [/ab/cd]" in test()
|
||||||
"reject [/abcdef]" in test("abcd:ef")
|
"accept [/abcdef]" in test("abcd:ef")
|
||||||
"reject [/abcdd/ef]" in test("abcdd:/ef")
|
"accept [/abcdd/ef]" in test("abcdd:/ef")
|
||||||
}
|
}
|
||||||
|
|
||||||
"""pathPrefix("ab(cd)".r)""" should {
|
"""pathPrefix("ab(cd)".r)""" should {
|
||||||
val test = testFor(pathPrefix("ab(cd)+".r) { echoCaptureAndUnmatchedPath })
|
val test = testFor(pathPrefix("ab(cd)+".r) { echoCaptureAndUnmatchedPath })
|
||||||
"reject [/bar]" in test()
|
"reject [/bar]" in test()
|
||||||
"reject [/ab/cd]" in test()
|
"reject [/ab/cd]" in test()
|
||||||
"reject [/abcdef]" in test("cd:ef")
|
"accept [/abcdef]" in test("cd:ef")
|
||||||
"reject [/abcde/fg]" in test("cd:e/fg")
|
"accept [/abcde/fg]" in test("cd:e/fg")
|
||||||
}
|
}
|
||||||
|
|
||||||
"pathPrefix(regex)" should {
|
"pathPrefix(regex)" should {
|
||||||
|
|
@ -132,40 +132,40 @@ class PathDirectivesSpec extends RoutingSpec with Inside {
|
||||||
val test = testFor(pathPrefix(separateOnSlashes("a/b")) { echoUnmatchedPath })
|
val test = testFor(pathPrefix(separateOnSlashes("a/b")) { echoUnmatchedPath })
|
||||||
"accept [/a/b]" in test("")
|
"accept [/a/b]" in test("")
|
||||||
"accept [/a/b/]" in test("/")
|
"accept [/a/b/]" in test("/")
|
||||||
"accept [/a/c]" in test()
|
"reject [/a/c]" in test()
|
||||||
}
|
}
|
||||||
"""pathPrefix(separateOnSlashes("abc"))""" should {
|
"""pathPrefix(separateOnSlashes("abc"))""" should {
|
||||||
val test = testFor(pathPrefix(separateOnSlashes("abc")) { echoUnmatchedPath })
|
val test = testFor(pathPrefix(separateOnSlashes("abc")) { echoUnmatchedPath })
|
||||||
"accept [/abc]" in test("")
|
"accept [/abc]" in test("")
|
||||||
"accept [/abcdef]" in test("def")
|
"accept [/abcdef]" in test("def")
|
||||||
"accept [/ab]" in test()
|
"reject [/ab]" in test()
|
||||||
}
|
}
|
||||||
|
|
||||||
"""pathPrefixTest("a" / Segment ~ Slash)""" should {
|
"""pathPrefixTest("a" / Segment ~ Slash)""" should {
|
||||||
val test = testFor(pathPrefixTest("a" / Segment ~ Slash) { echoCaptureAndUnmatchedPath })
|
val test = testFor(pathPrefixTest("a" / Segment ~ Slash) { echoCaptureAndUnmatchedPath })
|
||||||
"accept [/a/bc/]" in test("bc:/a/bc/")
|
"accept [/a/bc/]" in test("bc:/a/bc/")
|
||||||
"accept [/a/bc]" in test()
|
"reject [/a/bc]" in test()
|
||||||
"accept [/a/]" in test()
|
"reject [/a/]" in test()
|
||||||
}
|
}
|
||||||
|
|
||||||
"""pathSuffix("edit" / Segment)""" should {
|
"""pathSuffix("edit" / Segment)""" should {
|
||||||
val test = testFor(pathSuffix("edit" / Segment) { echoCaptureAndUnmatchedPath })
|
val test = testFor(pathSuffix("edit" / Segment) { echoCaptureAndUnmatchedPath })
|
||||||
"accept [/orders/123/edit]" in test("123:/orders/")
|
"accept [/orders/123/edit]" in test("123:/orders/")
|
||||||
"accept [/orders/123/ed]" in test()
|
"reject [/orders/123/ed]" in test()
|
||||||
"accept [/edit]" in test()
|
"reject [/edit]" in test()
|
||||||
}
|
}
|
||||||
|
|
||||||
"""pathSuffix("foo" / "bar" ~ "baz")""" should {
|
"""pathSuffix("foo" / "bar" ~ "baz")""" should {
|
||||||
val test = testFor(pathSuffix("foo" / "bar" ~ "baz") { echoUnmatchedPath })
|
val test = testFor(pathSuffix("foo" / "bar" ~ "baz") { echoUnmatchedPath })
|
||||||
"accept [/orders/barbaz/foo]" in test("/orders/")
|
"accept [/orders/barbaz/foo]" in test("/orders/")
|
||||||
"accept [/orders/bazbar/foo]" in test()
|
"reject [/orders/bazbar/foo]" in test()
|
||||||
}
|
}
|
||||||
|
|
||||||
"pathSuffixTest(Slash)" should {
|
"pathSuffixTest(Slash)" should {
|
||||||
val test = testFor(pathSuffixTest(Slash) { echoUnmatchedPath })
|
val test = testFor(pathSuffixTest(Slash) { echoUnmatchedPath })
|
||||||
"accept [/]" in test("/")
|
"accept [/]" in test("/")
|
||||||
"accept [/foo/]" in test("/foo/")
|
"accept [/foo/]" in test("/foo/")
|
||||||
"accept [/foo]" in test()
|
"reject [/foo]" in test()
|
||||||
}
|
}
|
||||||
|
|
||||||
"""pathPrefix("foo" | "bar")""" should {
|
"""pathPrefix("foo" | "bar")""" should {
|
||||||
|
|
@ -242,6 +242,20 @@ class PathDirectivesSpec extends RoutingSpec with Inside {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""rawPathPrefix(Slash ~ "a" / Segment ~ Slash)""" should {
|
||||||
|
val test = testFor(rawPathPrefix(Slash ~ "a" / Segment ~ Slash) { echoCaptureAndUnmatchedPath })
|
||||||
|
"accept [/a/bc/]" in test("bc:")
|
||||||
|
"reject [/a/bc]" in test()
|
||||||
|
"reject [/ab/]" in test()
|
||||||
|
}
|
||||||
|
|
||||||
|
"""rawPathPrefixTest(Slash ~ "a" / Segment ~ Slash)""" should {
|
||||||
|
val test = testFor(rawPathPrefixTest(Slash ~ "a" / Segment ~ Slash) { echoCaptureAndUnmatchedPath })
|
||||||
|
"accept [/a/bc/]" in test("bc:/a/bc/")
|
||||||
|
"reject [/a/bc]" in test()
|
||||||
|
"reject [/ab/]" in test()
|
||||||
|
}
|
||||||
|
|
||||||
"PathMatchers" should {
|
"PathMatchers" should {
|
||||||
{
|
{
|
||||||
val test = testFor(path(Rest.tmap { case Tuple1(s) ⇒ Tuple1(s.split('-').toList) }) { echoComplete })
|
val test = testFor(path(Rest.tmap { case Tuple1(s) ⇒ Tuple1(s.split('-').toList) }) { echoComplete })
|
||||||
|
|
@ -270,8 +284,17 @@ class PathDirectivesSpec extends RoutingSpec with Inside {
|
||||||
|
|
||||||
case class testFor(route: Route) {
|
case class testFor(route: Route) {
|
||||||
def apply(expectedResponse: String = null): String ⇒ Unit = exampleString ⇒
|
def apply(expectedResponse: String = null): String ⇒ Unit = exampleString ⇒
|
||||||
"\\[([^\\]]+)\\]".r.findFirstMatchIn(exampleString) match {
|
"""(accept|reject)\s+\[([^\]]+)\]""".r.findFirstMatchIn(exampleString) match {
|
||||||
case Some(uri) ⇒ Get(uri.group(1)) ~> route ~> check {
|
case Some(uri) ⇒
|
||||||
|
uri.group(1) match {
|
||||||
|
case "accept" if expectedResponse eq null ⇒
|
||||||
|
failTest("Example '" + exampleString + "' was missing an expectedResponse")
|
||||||
|
case "reject" if expectedResponse ne null ⇒
|
||||||
|
failTest("Example '" + exampleString + "' had an expectedResponse")
|
||||||
|
case _ ⇒
|
||||||
|
}
|
||||||
|
|
||||||
|
Get(uri.group(2)) ~> route ~> check {
|
||||||
if (expectedResponse eq null) handled shouldEqual false
|
if (expectedResponse eq null) handled shouldEqual false
|
||||||
else responseAs[String] shouldEqual expectedResponse
|
else responseAs[String] shouldEqual expectedResponse
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ object PathMatcher extends ImplicitPathMatcherConstruction {
|
||||||
else Unmatched
|
else Unmatched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Provoke implicit conversions to PathMatcher to be applied */
|
||||||
def apply[L](magnet: PathMatcher[L]): PathMatcher[L] = magnet
|
def apply[L](magnet: PathMatcher[L]): PathMatcher[L] = magnet
|
||||||
|
|
||||||
implicit class PathMatcher1Ops[T](matcher: PathMatcher1[T]) {
|
implicit class PathMatcher1Ops[T](matcher: PathMatcher1[T]) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ package akka.http.scaladsl.unmarshalling
|
||||||
|
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
import scala.collection.immutable.VectorBuilder
|
import scala.collection.immutable.VectorBuilder
|
||||||
import scala.concurrent.ExecutionContext
|
|
||||||
import akka.util.ByteString
|
import akka.util.ByteString
|
||||||
import akka.event.{ NoLogging, LoggingAdapter }
|
import akka.event.{ NoLogging, LoggingAdapter }
|
||||||
import akka.stream.impl.fusing.IteratorInterpreter
|
import akka.stream.impl.fusing.IteratorInterpreter
|
||||||
|
|
@ -21,9 +20,9 @@ import HttpCharsets._
|
||||||
|
|
||||||
trait MultipartUnmarshallers {
|
trait MultipartUnmarshallers {
|
||||||
|
|
||||||
implicit def defaultMultipartGeneralUnmarshaller(implicit ec: ExecutionContext, log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.General] =
|
implicit def defaultMultipartGeneralUnmarshaller(implicit log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.General] =
|
||||||
multipartGeneralUnmarshaller(`UTF-8`)
|
multipartGeneralUnmarshaller(`UTF-8`)
|
||||||
def multipartGeneralUnmarshaller(defaultCharset: HttpCharset)(implicit ec: ExecutionContext, log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.General] =
|
def multipartGeneralUnmarshaller(defaultCharset: HttpCharset)(implicit log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.General] =
|
||||||
multipartUnmarshaller[Multipart.General, Multipart.General.BodyPart, Multipart.General.BodyPart.Strict](
|
multipartUnmarshaller[Multipart.General, Multipart.General.BodyPart, Multipart.General.BodyPart.Strict](
|
||||||
mediaRange = `multipart/*`,
|
mediaRange = `multipart/*`,
|
||||||
defaultContentType = ContentTypes.`text/plain` withCharset defaultCharset,
|
defaultContentType = ContentTypes.`text/plain` withCharset defaultCharset,
|
||||||
|
|
@ -32,7 +31,7 @@ trait MultipartUnmarshallers {
|
||||||
createStrictBodyPart = Multipart.General.BodyPart.Strict,
|
createStrictBodyPart = Multipart.General.BodyPart.Strict,
|
||||||
createStrict = Multipart.General.Strict)
|
createStrict = Multipart.General.Strict)
|
||||||
|
|
||||||
implicit def multipartFormDataUnmarshaller(implicit ec: ExecutionContext, log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.FormData] =
|
implicit def multipartFormDataUnmarshaller(implicit log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.FormData] =
|
||||||
multipartUnmarshaller[Multipart.FormData, Multipart.FormData.BodyPart, Multipart.FormData.BodyPart.Strict](
|
multipartUnmarshaller[Multipart.FormData, Multipart.FormData.BodyPart, Multipart.FormData.BodyPart.Strict](
|
||||||
mediaRange = `multipart/form-data`,
|
mediaRange = `multipart/form-data`,
|
||||||
defaultContentType = ContentTypes.`application/octet-stream`,
|
defaultContentType = ContentTypes.`application/octet-stream`,
|
||||||
|
|
@ -41,9 +40,9 @@ trait MultipartUnmarshallers {
|
||||||
createStrictBodyPart = (entity, headers) ⇒ Multipart.General.BodyPart.Strict(entity, headers).toFormDataBodyPart.get,
|
createStrictBodyPart = (entity, headers) ⇒ Multipart.General.BodyPart.Strict(entity, headers).toFormDataBodyPart.get,
|
||||||
createStrict = (_, parts) ⇒ Multipart.FormData.Strict(parts))
|
createStrict = (_, parts) ⇒ Multipart.FormData.Strict(parts))
|
||||||
|
|
||||||
implicit def defaultMultipartByteRangesUnmarshaller(implicit ec: ExecutionContext, log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.ByteRanges] =
|
implicit def defaultMultipartByteRangesUnmarshaller(implicit log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.ByteRanges] =
|
||||||
multipartByteRangesUnmarshaller(`UTF-8`)
|
multipartByteRangesUnmarshaller(`UTF-8`)
|
||||||
def multipartByteRangesUnmarshaller(defaultCharset: HttpCharset)(implicit ec: ExecutionContext, log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.ByteRanges] =
|
def multipartByteRangesUnmarshaller(defaultCharset: HttpCharset)(implicit log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[Multipart.ByteRanges] =
|
||||||
multipartUnmarshaller[Multipart.ByteRanges, Multipart.ByteRanges.BodyPart, Multipart.ByteRanges.BodyPart.Strict](
|
multipartUnmarshaller[Multipart.ByteRanges, Multipart.ByteRanges.BodyPart, Multipart.ByteRanges.BodyPart.Strict](
|
||||||
mediaRange = `multipart/byteranges`,
|
mediaRange = `multipart/byteranges`,
|
||||||
defaultContentType = ContentTypes.`text/plain` withCharset defaultCharset,
|
defaultContentType = ContentTypes.`text/plain` withCharset defaultCharset,
|
||||||
|
|
@ -57,7 +56,7 @@ trait MultipartUnmarshallers {
|
||||||
createBodyPart: (BodyPartEntity, List[HttpHeader]) ⇒ BP,
|
createBodyPart: (BodyPartEntity, List[HttpHeader]) ⇒ BP,
|
||||||
createStreamed: (MultipartMediaType, Source[BP, Any]) ⇒ T,
|
createStreamed: (MultipartMediaType, Source[BP, Any]) ⇒ T,
|
||||||
createStrictBodyPart: (HttpEntity.Strict, List[HttpHeader]) ⇒ BPS,
|
createStrictBodyPart: (HttpEntity.Strict, List[HttpHeader]) ⇒ BPS,
|
||||||
createStrict: (MultipartMediaType, immutable.Seq[BPS]) ⇒ T)(implicit ec: ExecutionContext, log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[T] =
|
createStrict: (MultipartMediaType, immutable.Seq[BPS]) ⇒ T)(implicit log: LoggingAdapter = NoLogging): FromEntityUnmarshaller[T] =
|
||||||
Unmarshaller { implicit ec ⇒
|
Unmarshaller { implicit ec ⇒
|
||||||
entity ⇒
|
entity ⇒
|
||||||
if (entity.contentType.mediaType.isMultipart && mediaRange.matches(entity.contentType.mediaType)) {
|
if (entity.contentType.mediaType.isMultipart && mediaRange.matches(entity.contentType.mediaType)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue