=htj #16436 add missing Java directives
This commit is contained in:
parent
10ea40b2f8
commit
83833ae4f8
59 changed files with 2595 additions and 236 deletions
|
|
@ -40,4 +40,9 @@ public abstract class StatusCode {
|
|||
* a non-empty entity.
|
||||
*/
|
||||
public abstract boolean allowsEntity();
|
||||
|
||||
/**
|
||||
* Returns if the status-code is a redirection status code.
|
||||
*/
|
||||
public abstract boolean isRedirection();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ package akka.http.impl.util
|
|||
|
||||
import java.net.InetAddress
|
||||
import java.{ util ⇒ ju, lang ⇒ jl }
|
||||
import akka.http.scaladsl.model.ws.Message
|
||||
import akka.stream.javadsl
|
||||
import akka.stream.scaladsl
|
||||
|
||||
import scala.collection.immutable
|
||||
import scala.reflect.ClassTag
|
||||
import akka.japi
|
||||
|
|
@ -52,6 +56,9 @@ object JavaMapping {
|
|||
def asJava: J
|
||||
}
|
||||
|
||||
def toJava[J, S](s: S)(implicit mapping: JavaMapping[J, S]): J = mapping.toJava(s)
|
||||
def toScala[J, S](j: J)(implicit mapping: JavaMapping[J, S]): S = mapping.toScala(j)
|
||||
|
||||
object Implicits {
|
||||
import scala.language.implicitConversions
|
||||
|
||||
|
|
@ -87,6 +94,16 @@ object JavaMapping {
|
|||
def toJava(scalaObject: Option[_S]): japi.Option[_J] = japi.Option.fromScalaOption(scalaObject.map(mapping.toJava(_)))
|
||||
}
|
||||
|
||||
implicit def flowMapping[JIn, SIn, JOut, SOut, M](implicit inMapping: JavaMapping[JIn, SIn], outMapping: JavaMapping[JOut, SOut]): JavaMapping[javadsl.Flow[JIn, JOut, M], scaladsl.Flow[SIn, SOut, M]] =
|
||||
new JavaMapping[javadsl.Flow[JIn, JOut, M], scaladsl.Flow[SIn, SOut, M]] {
|
||||
def toScala(javaObject: javadsl.Flow[JIn, JOut, M]): S =
|
||||
scaladsl.Flow[SIn].map(inMapping.toJava).viaMat(javaObject)(scaladsl.Keep.right).map(outMapping.toScala)
|
||||
def toJava(scalaObject: scaladsl.Flow[SIn, SOut, M]): J =
|
||||
javadsl.Flow.wrap {
|
||||
scaladsl.Flow[JIn].map(inMapping.toScala).viaMat(scalaObject)(scaladsl.Keep.right).map(outMapping.toJava)
|
||||
}
|
||||
}
|
||||
|
||||
implicit object StringIdentity extends Identity[String]
|
||||
|
||||
implicit object LongMapping extends JavaMapping[jl.Long, Long] {
|
||||
|
|
@ -144,6 +161,11 @@ object JavaMapping {
|
|||
implicit object ProductVersion extends Inherited[jm.headers.ProductVersion, sm.headers.ProductVersion]
|
||||
implicit object RangeUnit extends Inherited[jm.headers.RangeUnit, sm.headers.RangeUnit]
|
||||
|
||||
implicit object WsMessage extends JavaMapping[jm.ws.Message, sm.ws.Message] {
|
||||
def toScala(javaObject: J): WsMessage.S = javaObject.asScala
|
||||
def toJava(scalaObject: Message): WsMessage.J = jm.ws.Message.adapt(scalaObject)
|
||||
}
|
||||
|
||||
implicit object Uri extends JavaMapping[jm.Uri, sm.Uri] {
|
||||
def toScala(javaObject: jm.Uri): Uri.S = cast[JavaUri](javaObject).uri
|
||||
def toJava(scalaObject: sm.Uri): Uri.J = JavaAccessors.Uri(scalaObject)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ sealed abstract class StatusCode extends jm.StatusCode with LazyValueBytesRender
|
|||
def defaultMessage: String
|
||||
def isSuccess: Boolean
|
||||
def isFailure: Boolean
|
||||
def isRedirection: Boolean
|
||||
def allowsEntity: Boolean
|
||||
}
|
||||
|
||||
|
|
@ -35,16 +36,25 @@ object StatusCodes extends ObjectRegistry[Int, StatusCode] {
|
|||
sealed protected abstract class HttpFailure extends StatusCode {
|
||||
def isSuccess = false
|
||||
def isFailure = true
|
||||
def isRedirection: Boolean = false
|
||||
|
||||
def allowsEntity = true
|
||||
}
|
||||
|
||||
// format: OFF
|
||||
final case class Informational private[StatusCodes] (intValue: Int)(val reason: String,
|
||||
val defaultMessage: String) extends HttpSuccess { def allowsEntity = false }
|
||||
val defaultMessage: String) extends HttpSuccess {
|
||||
def allowsEntity = false
|
||||
def isRedirection: Boolean = false
|
||||
}
|
||||
final case class Success private[StatusCodes] (intValue: Int)(val reason: String, val defaultMessage: String,
|
||||
val allowsEntity: Boolean = true) extends HttpSuccess
|
||||
val allowsEntity: Boolean = true) extends HttpSuccess {
|
||||
def isRedirection: Boolean = false
|
||||
}
|
||||
final case class Redirection private[StatusCodes] (intValue: Int)(val reason: String, val defaultMessage: String,
|
||||
val htmlTemplate: String, val allowsEntity: Boolean = true) extends HttpSuccess
|
||||
val htmlTemplate: String, val allowsEntity: Boolean = true) extends HttpSuccess {
|
||||
def isRedirection: Boolean = true
|
||||
}
|
||||
final case class ClientError private[StatusCodes] (intValue: Int)(val reason: String, val defaultMessage: String) extends HttpFailure
|
||||
final case class ServerError private[StatusCodes] (intValue: Int)(val reason: String, val defaultMessage: String) extends HttpFailure
|
||||
|
||||
|
|
@ -54,6 +64,7 @@ object StatusCodes extends ObjectRegistry[Int, StatusCode] {
|
|||
val isSuccess: Boolean,
|
||||
val allowsEntity: Boolean) extends StatusCode {
|
||||
def isFailure: Boolean = !isSuccess
|
||||
def isRedirection: Boolean = false
|
||||
}
|
||||
|
||||
private def reg[T <: StatusCode](code: T): T = {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
package akka.http.scaladsl.model.ws
|
||||
|
||||
import java.lang.Iterable
|
||||
import akka.http.impl.util.JavaMapping
|
||||
|
||||
import scala.collection.immutable
|
||||
import akka.stream
|
||||
import akka.stream.javadsl
|
||||
|
|
@ -63,13 +65,13 @@ trait UpgradeToWebsocket extends jm.ws.UpgradeToWebsocket {
|
|||
* Java API
|
||||
*/
|
||||
def handleMessagesWith(handlerFlow: stream.javadsl.Flow[jm.ws.Message, jm.ws.Message, _]): HttpResponse =
|
||||
handleMessages(adaptJavaFlow(handlerFlow))
|
||||
handleMessages(JavaMapping.toScala(handlerFlow))
|
||||
|
||||
/**
|
||||
* Java API
|
||||
*/
|
||||
def handleMessagesWith(handlerFlow: stream.javadsl.Flow[jm.ws.Message, jm.ws.Message, _], subprotocol: String): HttpResponse =
|
||||
handleMessages(adaptJavaFlow(handlerFlow), subprotocol = Some(subprotocol))
|
||||
handleMessages(JavaMapping.toScala(handlerFlow), subprotocol = Some(subprotocol))
|
||||
|
||||
/**
|
||||
* Java API
|
||||
|
|
@ -85,8 +87,6 @@ trait UpgradeToWebsocket extends jm.ws.UpgradeToWebsocket {
|
|||
subprotocol: String): HttpResponse =
|
||||
handleMessages(createScalaFlow(inSink, outSource), subprotocol = Some(subprotocol))
|
||||
|
||||
private[this] def adaptJavaFlow(handlerFlow: stream.javadsl.Flow[jm.ws.Message, jm.ws.Message, _]): Flow[Message, Message, Any] =
|
||||
Flow[Message].map(jm.ws.Message.adapt).via(handlerFlow.asScala).map(_.asScala)
|
||||
private[this] def createScalaFlow(inSink: stream.javadsl.Sink[jm.ws.Message, _], outSource: stream.javadsl.Source[jm.ws.Message, _]): Flow[Message, Message, Any] =
|
||||
adaptJavaFlow(Flow.wrap(inSink.asScala, outSource.asScala)((_, _) ⇒ ()).asJava)
|
||||
JavaMapping.toScala(Flow.wrap(inSink.asScala, outSource.asScala)((_, _) ⇒ ()).asJava)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package akka.http.javadsl.testkit
|
||||
|
||||
import akka.http.javadsl.server._
|
||||
import Directives._
|
||||
import org.junit.rules.ExternalResource
|
||||
import org.junit.{ Rule, Assert }
|
||||
import scala.concurrent.duration._
|
||||
|
|
@ -35,6 +37,11 @@ abstract class JUnitRouteTestBase extends RouteTest {
|
|||
throw new IllegalStateException("Assertion should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
protected def completeWithValueToString[T](value: RequestVal[T]): Route =
|
||||
handleWith(value, new Handler1[T] {
|
||||
def handle(ctx: RequestContext, t: T): RouteResult = ctx.complete(t.toString)
|
||||
})
|
||||
}
|
||||
abstract class JUnitRouteTest extends JUnitRouteTestBase {
|
||||
private[this] val _systemResource = new ActorSystemResource
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@ abstract class RouteTest extends AllDirectives {
|
|||
|
||||
protected def awaitDuration: FiniteDuration = 500.millis
|
||||
|
||||
def runRoute(route: Route, request: HttpRequest): TestResponse = {
|
||||
val scalaRoute = ScalaRoute.seal(RouteImplementation(route))
|
||||
def runRoute(route: Route, request: HttpRequest): TestResponse =
|
||||
runScalaRoute(ScalaRoute.seal(RouteImplementation(route)), request)
|
||||
def runRouteUnSealed(route: Route, request: HttpRequest): TestResponse =
|
||||
runScalaRoute(RouteImplementation(route), request)
|
||||
|
||||
private def runScalaRoute(scalaRoute: ScalaRoute, request: HttpRequest): TestResponse = {
|
||||
val result = scalaRoute(new server.RequestContextImpl(request.asScala, NoLogging, RoutingSettings(system)))
|
||||
|
||||
result.awaitResult(awaitDuration) match {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import akka.http.javadsl.server.values.*;
|
|||
import java.io.IOException;
|
||||
|
||||
public class SimpleServerApp8 extends HttpApp {
|
||||
static Parameter<Integer> x = Parameters.integer("x");
|
||||
static Parameter<Integer> y = Parameters.integer("y");
|
||||
static Parameter<Integer> x = Parameters.intValue("x");
|
||||
static Parameter<Integer> y = Parameters.intValue("y");
|
||||
|
||||
static PathMatcher<Integer> xSegment = PathMatchers.integerNumber();
|
||||
static PathMatcher<Integer> ySegment = PathMatchers.integerNumber();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ import akka.http.javadsl.server.values.*;
|
|||
import static akka.http.javadsl.server.Directives.*;
|
||||
|
||||
public class HandlerBindingTest extends JUnitRouteTest {
|
||||
Parameter<Integer> aParam = Parameters.intValue("a");
|
||||
Parameter<Integer> bParam = Parameters.intValue("b");
|
||||
Parameter<Integer> cParam = Parameters.intValue("c");
|
||||
Parameter<Integer> dParam = Parameters.intValue("d");
|
||||
|
||||
@Test
|
||||
public void testHandlerWithoutExtractions() {
|
||||
Route route = handleWith(ctx -> ctx.complete("Ok"));
|
||||
|
|
@ -19,7 +24,7 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
}
|
||||
@Test
|
||||
public void testHandler1() {
|
||||
Route route = handleWith(Parameters.integer("a"), (ctx, a) -> ctx.complete("Ok " + a));
|
||||
Route route = handleWith(aParam, (ctx, a) -> ctx.complete("Ok " + a));
|
||||
TestResponse response = runRoute(route, HttpRequest.GET("?a=23"));
|
||||
response.assertStatusCode(200);
|
||||
response.assertEntity("Ok 23");
|
||||
|
|
@ -28,8 +33,8 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
public void testHandler2() {
|
||||
Route route =
|
||||
handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
aParam,
|
||||
bParam,
|
||||
(ctx, a, b) -> ctx.complete("Sum: " + (a + b)));
|
||||
TestResponse response = runRoute(route, HttpRequest.GET("?a=23&b=42"));
|
||||
response.assertStatusCode(200);
|
||||
|
|
@ -39,9 +44,9 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
public void testHandler3() {
|
||||
Route route =
|
||||
handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
Parameters.integer("c"),
|
||||
aParam,
|
||||
bParam,
|
||||
cParam,
|
||||
(ctx, a, b, c) -> ctx.complete("Sum: " + (a + b + c)));
|
||||
TestResponse response = runRoute(route, HttpRequest.GET("?a=23&b=42&c=30"));
|
||||
response.assertStatusCode(200);
|
||||
|
|
@ -51,10 +56,10 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
public void testHandler4() {
|
||||
Route route =
|
||||
handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
Parameters.integer("c"),
|
||||
Parameters.integer("d"),
|
||||
aParam,
|
||||
bParam,
|
||||
cParam,
|
||||
dParam,
|
||||
(ctx, a, b, c, d) -> ctx.complete("Sum: " + (a + b + c + d)));
|
||||
TestResponse response = runRoute(route, HttpRequest.GET("?a=23&b=42&c=30&d=45"));
|
||||
response.assertStatusCode(200);
|
||||
|
|
@ -67,10 +72,10 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
public void testHandler4MethodRef() {
|
||||
Route route =
|
||||
handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
Parameters.integer("c"),
|
||||
Parameters.integer("d"),
|
||||
aParam,
|
||||
bParam,
|
||||
cParam,
|
||||
dParam,
|
||||
this::sum);
|
||||
TestResponse response = runRoute(route, HttpRequest.GET("?a=23&b=42&c=30&d=45"));
|
||||
response.assertStatusCode(200);
|
||||
|
|
|
|||
|
|
@ -5,17 +5,20 @@
|
|||
package akka.http.javadsl.server.examples.simple;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.dispatch.Futures;
|
||||
import akka.http.javadsl.server.*;
|
||||
import akka.http.javadsl.server.values.Parameter;
|
||||
import akka.http.javadsl.server.values.Parameters;
|
||||
import akka.http.javadsl.server.values.PathMatcher;
|
||||
import akka.http.javadsl.server.values.PathMatchers;
|
||||
import scala.concurrent.Future;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class SimpleServerApp extends HttpApp {
|
||||
static Parameter<Integer> x = Parameters.integer("x");
|
||||
static Parameter<Integer> y = Parameters.integer("y");
|
||||
static Parameter<Integer> x = Parameters.intValue("x");
|
||||
static Parameter<Integer> y = Parameters.intValue("y");
|
||||
|
||||
static PathMatcher<Integer> xSegment = PathMatchers.integerNumber();
|
||||
static PathMatcher<Integer> ySegment = PathMatchers.integerNumber();
|
||||
|
|
@ -24,6 +27,13 @@ public class SimpleServerApp extends HttpApp {
|
|||
int result = x * y;
|
||||
return ctx.complete(String.format("%d * %d = %d", x, y, result));
|
||||
}
|
||||
public static Future<RouteResult> multiplyAsync(final RequestContext ctx, final int x, final int y) {
|
||||
return Futures.future(new Callable<RouteResult>() {
|
||||
public RouteResult call() throws Exception {
|
||||
return multiply(ctx, x, y);
|
||||
}
|
||||
}, ctx.executionContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Route createRoute() {
|
||||
|
|
@ -59,6 +69,10 @@ public class SimpleServerApp extends HttpApp {
|
|||
path("multiply", xSegment, ySegment).route(
|
||||
// bind handler by reflection
|
||||
handleWith(SimpleServerApp.class, "multiply", xSegment, ySegment)
|
||||
),
|
||||
path("multiplyAsync", xSegment, ySegment).route(
|
||||
// bind async handler by reflection
|
||||
handleWith(SimpleServerApp.class, "multiplyAsync", xSegment, ySegment)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ public class CompleteTest extends JUnitRouteTest {
|
|||
}
|
||||
@Test
|
||||
public void completeWithFuture() {
|
||||
Parameter<Integer> x = Parameters.integer("x");
|
||||
Parameter<Integer> y = Parameters.integer("y");
|
||||
Parameter<Integer> x = Parameters.intValue("x");
|
||||
Parameter<Integer> y = Parameters.intValue("y");
|
||||
|
||||
Handler2<Integer, Integer> slowCalc = new Handler2<Integer, Integer>() {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
}
|
||||
@Test
|
||||
public void testHandlerWithSomeExtractions() {
|
||||
final Parameter<Integer> a = Parameters.integer("a");
|
||||
final Parameter<Integer> b = Parameters.integer("b");
|
||||
final Parameter<Integer> a = Parameters.intValue("a");
|
||||
final Parameter<Integer> b = Parameters.intValue("b");
|
||||
|
||||
Route route = handleWith(
|
||||
new Handler() {
|
||||
|
|
@ -42,7 +42,7 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
}
|
||||
@Test
|
||||
public void testHandlerIfExtractionFails() {
|
||||
final Parameter<Integer> a = Parameters.integer("a");
|
||||
final Parameter<Integer> a = Parameters.intValue("a");
|
||||
|
||||
Route route = handleWith(
|
||||
new Handler() {
|
||||
|
|
@ -58,7 +58,7 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
}
|
||||
@Test
|
||||
public void testHandler1() {
|
||||
final Parameter<Integer> a = Parameters.integer("a");
|
||||
final Parameter<Integer> a = Parameters.intValue("a");
|
||||
|
||||
Route route = handleWith(
|
||||
a,
|
||||
|
|
@ -76,8 +76,8 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
@Test
|
||||
public void testHandler2() {
|
||||
Route route = handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
Parameters.intValue("a"),
|
||||
Parameters.intValue("b"),
|
||||
new Handler2<Integer, Integer>() {
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Integer a, Integer b) {
|
||||
|
|
@ -92,9 +92,9 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
@Test
|
||||
public void testHandler3() {
|
||||
Route route = handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
Parameters.integer("c"),
|
||||
Parameters.intValue("a"),
|
||||
Parameters.intValue("b"),
|
||||
Parameters.intValue("c"),
|
||||
new Handler3<Integer, Integer, Integer>() {
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Integer a, Integer b, Integer c) {
|
||||
|
|
@ -109,10 +109,10 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
@Test
|
||||
public void testHandler4() {
|
||||
Route route = handleWith(
|
||||
Parameters.integer("a"),
|
||||
Parameters.integer("b"),
|
||||
Parameters.integer("c"),
|
||||
Parameters.integer("d"),
|
||||
Parameters.intValue("a"),
|
||||
Parameters.intValue("b"),
|
||||
Parameters.intValue("c"),
|
||||
Parameters.intValue("d"),
|
||||
new Handler4<Integer, Integer, Integer, Integer>() {
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Integer a, Integer b, Integer c, Integer d) {
|
||||
|
|
@ -131,7 +131,7 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
return ctx.complete("Negated: " + (- a));
|
||||
}
|
||||
}
|
||||
Route route = handleWith(new Test(), "negate", Parameters.integer("a"));
|
||||
Route route = handleWith(new Test(), "negate", Parameters.intValue("a"));
|
||||
runRoute(route, HttpRequest.GET("?a=23"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Negated: -23");
|
||||
|
|
@ -142,7 +142,7 @@ public class HandlerBindingTest extends JUnitRouteTest {
|
|||
}
|
||||
@Test
|
||||
public void testStaticReflectiveHandler() {
|
||||
Route route = handleWith(HandlerBindingTest.class, "squared", Parameters.integer("a"));
|
||||
Route route = handleWith(HandlerBindingTest.class, "squared", Parameters.intValue("a"));
|
||||
runRoute(route, HttpRequest.GET("?a=23"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Squared: 529");
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import akka.http.javadsl.model.headers.ContentEncoding;
|
|||
import akka.http.javadsl.model.headers.HttpEncodings;
|
||||
import akka.http.javadsl.server.Coder;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.http.javadsl.server.*;
|
||||
import akka.util.ByteString;
|
||||
import org.junit.*;
|
||||
import scala.concurrent.Await;
|
||||
|
|
@ -86,7 +87,53 @@ public class CodingDirectivesTest extends JUnitRouteTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAutomaticDecoding() {}
|
||||
public void testAutomaticDecoding() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
decodeRequest(
|
||||
completeWithValueToString(RequestVals.entityAs(Unmarshallers.String()))
|
||||
)
|
||||
);
|
||||
|
||||
HttpRequest deflateRequest =
|
||||
HttpRequest.POST("/")
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.DEFLATE))
|
||||
.withEntity(Coder.Deflate.encode(ByteString.fromString("abcdef")));
|
||||
route.run(deflateRequest)
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("abcdef");
|
||||
|
||||
HttpRequest gzipRequest =
|
||||
HttpRequest.POST("/")
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.GZIP))
|
||||
.withEntity(Coder.Gzip.encode(ByteString.fromString("hijklmnopq")));
|
||||
route.run(gzipRequest)
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("hijklmnopq");
|
||||
}
|
||||
@Test
|
||||
public void testGzipDecoding() {}
|
||||
public void testGzipDecoding() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
decodeRequestWith(Coder.Gzip,
|
||||
completeWithValueToString(RequestVals.entityAs(Unmarshallers.String()))
|
||||
)
|
||||
);
|
||||
|
||||
HttpRequest gzipRequest =
|
||||
HttpRequest.POST("/")
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.GZIP))
|
||||
.withEntity(Coder.Gzip.encode(ByteString.fromString("hijklmnopq")));
|
||||
route.run(gzipRequest)
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("hijklmnopq");
|
||||
|
||||
HttpRequest deflateRequest =
|
||||
HttpRequest.POST("/")
|
||||
.addHeader(ContentEncoding.create(HttpEncodings.DEFLATE))
|
||||
.withEntity(Coder.Deflate.encode(ByteString.fromString("abcdef")));
|
||||
route.run(deflateRequest)
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The request's Content-Encoding is not supported. Expected:\ngzip");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import akka.http.javadsl.testkit.*;
|
|||
public class ExecutionDirectivesTest extends JUnitRouteTest {
|
||||
@Test
|
||||
public void testCatchExceptionThrownFromHandler() {
|
||||
Parameter<Integer> a = Parameters.integer("a");
|
||||
Parameter<Integer> b = Parameters.integer("b");
|
||||
Parameter<Integer> a = Parameters.intValue("a");
|
||||
Parameter<Integer> b = Parameters.intValue("b");
|
||||
Handler2<Integer, Integer> divide =
|
||||
new Handler2<Integer, Integer>() {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import akka.japi.function.Function;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HostDirectivesTest extends JUnitRouteTest {
|
||||
@Test
|
||||
public void testHostFilterBySingleName() {
|
||||
TestRoute route = testRoute(host("example.org", complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("https://other.org")))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void testHostFilterByNames() {
|
||||
ArrayList<String> hosts = new ArrayList<String>();
|
||||
hosts.add("example.org");
|
||||
hosts.add("example2.org");
|
||||
TestRoute route = testRoute(host(hosts, complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example2.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("https://other.org")))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void testHostFilterByPredicate() {
|
||||
Function<String, Boolean> predicate =
|
||||
new Function<String, Boolean>(){
|
||||
@Override
|
||||
public Boolean apply(String hostName) throws Exception {
|
||||
return hostName.contains("ample");
|
||||
}
|
||||
};
|
||||
|
||||
TestRoute route = testRoute(host(predicate, complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("https://other.org")))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.server.RequestContext;
|
||||
import akka.http.javadsl.server.RequestVal;
|
||||
import akka.http.javadsl.server.RequestVals;
|
||||
import akka.http.javadsl.server.values.Parameter;
|
||||
import akka.http.javadsl.server.values.Parameters;
|
||||
import akka.http.javadsl.server.values.PathMatchers;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import akka.japi.function.Function;
|
||||
import akka.japi.function.Function2;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MiscDirectivesTest extends JUnitRouteTest {
|
||||
static Parameter<String> stringParam = Parameters.stringValue("stringParam");
|
||||
|
||||
static Function<String, Boolean> isShort =
|
||||
new Function<String, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(String str) throws Exception {
|
||||
return str.length() < 5;
|
||||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testValidateRequestContext() {
|
||||
Function<RequestContext, Boolean> hasShortPath =
|
||||
new Function<RequestContext, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(RequestContext ctx) throws Exception {
|
||||
return ctx.request().getUri().path().toString().length() < 5;
|
||||
}
|
||||
};
|
||||
|
||||
TestRoute route = testRoute(validate(hasShortPath, "Path too long!", complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("/abc")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("/abcdefghijkl")))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Path too long!");
|
||||
}
|
||||
@Test
|
||||
public void testValidateOneStandaloneRequestVal() {
|
||||
TestRoute route = testRoute(validate(stringParam, isShort, "stringParam too long!", complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("/?stringParam=abcd"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("/?stringParam=abcdefg"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("stringParam too long!");
|
||||
}
|
||||
@Test
|
||||
public void testValidateOnePathMatcherRequestVal() {
|
||||
RequestVal<String> nameSegment = PathMatchers.segment();
|
||||
|
||||
TestRoute route = testRoute(
|
||||
path("people", nameSegment, "address").route(
|
||||
validate(nameSegment, isShort, "Segment too long!", complete("OK!"))
|
||||
)
|
||||
);
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("/people/john/address"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("/people/hermanbaker/address"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Segment too long!");
|
||||
}
|
||||
@Test
|
||||
public void testValidateTwoRequestVals() {
|
||||
Function2<String, String, Boolean> stringParamEqualsHostName =
|
||||
new Function2<String, String, Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(String stringParam, String hostName) throws Exception {
|
||||
return stringParam.equals(hostName);
|
||||
}
|
||||
};
|
||||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
validate(stringParam, RequestVals.host(), stringParamEqualsHostName, "stringParam must equal hostName!",
|
||||
complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("http://example.org/?stringParam=example.org"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("http://blubber.org/?stringParam=example.org"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("stringParam must equal hostName!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.GET("http://blubber.org/"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package akka.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.values.PathMatcher;
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
@ -76,24 +77,140 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("hey", name).route(toStringEcho(name))
|
||||
path("hey", name).route(completeWithValueToString(name))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/hey/jude"))
|
||||
.assertEntity("jude");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathEnd() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
pathPrefix("test").route(
|
||||
pathEnd().route(complete("end")),
|
||||
path("abc").route(complete("abc"))
|
||||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/test"))
|
||||
.assertEntity("end");
|
||||
|
||||
route.run(HttpRequest.GET("/test/abc"))
|
||||
.assertEntity("abc");
|
||||
|
||||
route.run(HttpRequest.GET("/xyz"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void testSingleSlash() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
pathPrefix("test").route(
|
||||
pathSingleSlash().route(complete("Ok"))
|
||||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/"))
|
||||
route.run(HttpRequest.GET("/test/"))
|
||||
.assertEntity("Ok");
|
||||
|
||||
route.run(HttpRequest.GET("/test"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathEndOrSingleSlash() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
pathPrefix("test").route(
|
||||
pathEndOrSingleSlash().route(complete("Ok"))
|
||||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/test"))
|
||||
.assertEntity("Ok");
|
||||
|
||||
route.run(HttpRequest.GET("/test/"))
|
||||
.assertEntity("Ok");
|
||||
|
||||
route.run(HttpRequest.GET("/abc"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawPathPrefixTest() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
rawPathPrefixTest(PathMatchers.SLASH(), "abc").route(
|
||||
completeWithValueToString(RequestVals.unmatchedPath())
|
||||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/abc"))
|
||||
.assertEntity("/abc");
|
||||
|
||||
route.run(HttpRequest.GET("/abc/def"))
|
||||
.assertEntity("/abc/def");
|
||||
|
||||
route.run(HttpRequest.GET("/abcd/ef"))
|
||||
.assertEntity("/abcd/ef");
|
||||
|
||||
route.run(HttpRequest.GET("/xyz/def"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void testPathPrefixTest() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
pathPrefixTest("abc").route(completeWithValueToString(RequestVals.unmatchedPath()))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/abc"))
|
||||
.assertEntity("/abc");
|
||||
|
||||
route.run(HttpRequest.GET("/abc/def"))
|
||||
.assertEntity("/abc/def");
|
||||
|
||||
route.run(HttpRequest.GET("/abcd/ef"))
|
||||
.assertEntity("/abcd/ef");
|
||||
|
||||
route.run(HttpRequest.GET("/xyz/def"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void testPathSuffix() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
pathSuffix(PathMatchers.SLASH(), "abc").route(completeWithValueToString(RequestVals.unmatchedPath()))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/test/abc/"))
|
||||
.assertEntity("/test/");
|
||||
|
||||
route.run(HttpRequest.GET("/abc/"))
|
||||
.assertEntity("/");
|
||||
|
||||
route.run(HttpRequest.GET("/abc/def"))
|
||||
.assertStatusCode(404);
|
||||
|
||||
route.run(HttpRequest.GET("/abc"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void testPathSuffixTest() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
pathSuffixTest("abc").route(completeWithValueToString(RequestVals.unmatchedPath()))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/test/abc"))
|
||||
.assertEntity("/test/abc");
|
||||
|
||||
route.run(HttpRequest.GET("/abc"))
|
||||
.assertEntity("/abc");
|
||||
|
||||
route.run(HttpRequest.GET("/abc/def"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +220,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("age", age).route(toStringEcho(age))
|
||||
path("age", age).route(completeWithValueToString(age))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/age/38"))
|
||||
|
|
@ -112,7 +229,6 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
route.run(HttpRequest.GET("/age/abc"))
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoVals() {
|
||||
// tests that `x` and `y` have different identities which is important for
|
||||
|
|
@ -122,7 +238,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("multiply", x, y).route(
|
||||
path("multiply", x, "with", y).route(
|
||||
handleWith(x, y, new Handler2<Integer, Integer>() {
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Integer x, Integer y) {
|
||||
|
|
@ -132,7 +248,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/multiply/3/6"))
|
||||
route.run(HttpRequest.GET("/multiply/3/with/6"))
|
||||
.assertEntity("3 * 6 = 18");
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +258,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("color", color).route(toStringEcho(color))
|
||||
path("color", color).route(completeWithValueToString(color))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/color/a0c2ef"))
|
||||
|
|
@ -155,7 +271,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("bigage", bigAge).route(toStringEcho(bigAge))
|
||||
path("bigage", bigAge).route(completeWithValueToString(bigAge))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/bigage/12345678901"))
|
||||
|
|
@ -168,7 +284,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("code", code).route(toStringEcho(code))
|
||||
path("code", code).route(completeWithValueToString(code))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/code/a0b1c2d3e4f5"))
|
||||
|
|
@ -181,7 +297,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("pets", rest).route(toStringEcho(rest))
|
||||
path("pets", rest).route(completeWithValueToString(rest))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/pets/afdaoisd/asda/sfasfasf/asf"))
|
||||
|
|
@ -194,7 +310,7 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("by-uuid", uuid).route(toStringEcho(uuid))
|
||||
path("by-uuid", uuid).route(completeWithValueToString(uuid))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/by-uuid/6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||
|
|
@ -207,19 +323,42 @@ public class PathDirectivesTest extends JUnitRouteTest {
|
|||
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
path("pets", segments).route(toStringEcho(segments))
|
||||
path("pets", segments).route(completeWithValueToString(segments))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/pets/cat/dog"))
|
||||
.assertEntity("[cat, dog]");
|
||||
}
|
||||
|
||||
private <T> Route toStringEcho(RequestVal<T> value) {
|
||||
return handleWith(value, new Handler1<T>() {
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, T t) {
|
||||
return ctx.complete(t.toString());
|
||||
}
|
||||
});
|
||||
@Test
|
||||
public void testRedirectToTrailingSlashIfMissing() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
redirectToTrailingSlashIfMissing(StatusCodes.FOUND, complete("Ok"))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/home"))
|
||||
.assertStatusCode(302)
|
||||
.assertHeaderExists("Location", "/home/");
|
||||
|
||||
route.run(HttpRequest.GET("/home/"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectToNoTrailingSlashIfPresent() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
redirectToNoTrailingSlashIfPresent(StatusCodes.FOUND, complete("Ok"))
|
||||
);
|
||||
|
||||
route.run(HttpRequest.GET("/home/"))
|
||||
.assertStatusCode(302)
|
||||
.assertHeaderExists("Location", "/home");
|
||||
|
||||
route.run(HttpRequest.GET("/home"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Ok");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.model.headers.Location;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import org.junit.Test;
|
||||
|
||||
public class RouteDirectivesTest extends JUnitRouteTest {
|
||||
@Test
|
||||
public void testRedirection() {
|
||||
Uri targetUri = Uri.create("http://example.com");
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
redirect(targetUri, StatusCodes.FOUND)
|
||||
);
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(302)
|
||||
.assertHeaderExists(Location.create(targetUri));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SchemeDirectivesTest extends JUnitRouteTest {
|
||||
@Test
|
||||
public void testSchemeFilter() {
|
||||
TestRoute route = testRoute(scheme("http", complete("OK!")));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("OK!");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("https://example.org")))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Uri scheme not allowed, supported schemes: http");
|
||||
}
|
||||
}
|
||||
|
|
@ -19,4 +19,13 @@ public class SimpleServerTest extends JUnitRouteTest {
|
|||
.assertStatusCode(200)
|
||||
.assertEntity("42 + 23 = 65");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplyAsync() {
|
||||
TestResponse response = route.run(HttpRequest.GET("/multiplyAsync/42/23"));
|
||||
|
||||
response
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("42 * 23 = 966");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values;
|
||||
|
||||
import akka.http.javadsl.model.DateTime;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.headers.HttpCookie;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CookiesTest extends JUnitRouteTest {
|
||||
Cookie userIdCookie = Cookies.create("userId").withDomain("example.com").withPath("/admin");
|
||||
|
||||
@Test
|
||||
public void testCookieValue() {
|
||||
TestRoute route =
|
||||
testRoute(completeWithValueToString(userIdCookie.value()));
|
||||
|
||||
route.run(HttpRequest.create())
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required cookie 'userId'");
|
||||
|
||||
route.run(HttpRequest.create().addHeader(akka.http.javadsl.model.headers.Cookie.create("userId", "12345")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("12345");
|
||||
}
|
||||
@Test
|
||||
public void testCookieOptionalValue() {
|
||||
TestRoute route =
|
||||
testRoute(completeWithValueToString(userIdCookie.optionalValue()));
|
||||
|
||||
route.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route.run(HttpRequest.create().addHeader(akka.http.javadsl.model.headers.Cookie.create("userId", "12345")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(12345)");
|
||||
}
|
||||
@Test
|
||||
public void testCookieSet() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
userIdCookie.set("12").route(
|
||||
complete("OK!")
|
||||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertHeaderExists("Set-Cookie", "userId=12; Domain=example.com; Path=/admin")
|
||||
.assertEntity("OK!");
|
||||
}
|
||||
@Test
|
||||
public void testDeleteCookie() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
userIdCookie.delete(
|
||||
complete("OK!")
|
||||
)
|
||||
);
|
||||
|
||||
route.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertHeaderExists("Set-Cookie", "userId=deleted; Expires=Wed, 01 Jan 1800 00:00:00 GMT; Domain=example.com; Path=/admin")
|
||||
.assertEntity("OK!");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.MediaTypes;
|
||||
import akka.http.javadsl.server.RequestVal;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import akka.japi.Option;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FormFieldsTest extends JUnitRouteTest {
|
||||
static FormField<String> stringParam = FormFields.stringValue("stringParam");
|
||||
static FormField<Byte> byteParam = FormFields.byteValue("byteParam");
|
||||
static FormField<Short> shortParam = FormFields.shortValue("shortParam");
|
||||
static FormField<Integer> intParam = FormFields.intValue("intParam");
|
||||
static FormField<Long> longParam = FormFields.longValue("longParam");
|
||||
static FormField<Float> floatParam = FormFields.floatValue("floatParam");
|
||||
static FormField<Double> doubleParam = FormFields.doubleValue("doubleParam");
|
||||
|
||||
static FormField<Byte> hexByteParam = FormFields.hexByteValue("hexByteParam");
|
||||
static FormField<Short> hexShortParam = FormFields.hexShortValue("hexShortParam");
|
||||
static FormField<Integer> hexIntParam = FormFields.hexIntValue("hexIntParam");
|
||||
static FormField<Long> hexLongParam = FormFields.hexLongValue("hexLongParam");
|
||||
|
||||
static RequestVal<String> nameWithDefault = FormFields.stringValue("nameWithDefault").withDefault("John Doe");
|
||||
static RequestVal<Option<Integer>> optionalIntParam = FormFields.intValue("optionalIntParam").optional();
|
||||
|
||||
private Map.Entry<String, String> entry(String name, String value) {
|
||||
return new AbstractMap.SimpleImmutableEntry<String, String>(name, value);
|
||||
}
|
||||
private HttpRequest urlEncodedRequest(Map.Entry<String, String>... entries) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean next = false;
|
||||
for (Map.Entry<String, String> entry: entries) {
|
||||
if (next) {
|
||||
sb.append('&');
|
||||
next = true;
|
||||
}
|
||||
sb.append(entry.getKey());
|
||||
sb.append('=');
|
||||
sb.append(entry.getValue());
|
||||
}
|
||||
|
||||
return
|
||||
HttpRequest.POST("/test")
|
||||
.withEntity(MediaTypes.APPLICATION_X_WWW_FORM_URLENCODED.toContentType(), sb.toString());
|
||||
}
|
||||
private HttpRequest singleParameterUrlEncodedRequest(String name, String value) {
|
||||
return urlEncodedRequest(entry(name, value));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(stringParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'stringParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("stringParam", "john"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(byteParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'byteParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("byteParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'byteParam' was malformed:\n'test' is not a valid 8-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("byteParam", "1000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'byteParam' was malformed:\n'1000' is not a valid 8-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("byteParam", "48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(shortParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'shortParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("shortParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'shortParam' was malformed:\n'test' is not a valid 16-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("shortParam", "100000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'shortParam' was malformed:\n'100000' is not a valid 16-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("shortParam", "1234"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("1234");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(intParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'intParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("intParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'intParam' was malformed:\n'test' is not a valid 32-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("intParam", "48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(longParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'longParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("longParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'longParam' was malformed:\n'test' is not a valid 64-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("longParam", "123456"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("123456");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(floatParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'floatParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("floatParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'floatParam' was malformed:\n'test' is not a valid 32-bit floating point value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("floatParam", "48.123"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48.123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(doubleParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'doubleParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("doubleParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'doubleParam' was malformed:\n'test' is not a valid 64-bit floating point value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("doubleParam", "0.234213235987"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("0.234213235987");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexByteFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexByteParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'hexByteParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexByteParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'hexByteParam' was malformed:\n'test' is not a valid 8-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexByteParam", "1000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'hexByteParam' was malformed:\n'1000' is not a valid 8-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexByteParam", "48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Integer.toString(0x48));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexShortFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexShortParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'hexShortParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexShortParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'hexShortParam' was malformed:\n'test' is not a valid 16-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexShortParam", "100000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'hexShortParam' was malformed:\n'100000' is not a valid 16-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexShortParam", "1234"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Integer.toString(0x1234));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexIntegerFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexIntParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'hexIntParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexIntParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'hexIntParam' was malformed:\n'test' is not a valid 32-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexIntParam", "12345678"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Integer.toString(0x12345678));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexLongFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexLongParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required form field 'hexLongParam'");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexLongParam", "test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The form field 'hexLongParam' was malformed:\n'test' is not a valid 64-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("hexLongParam", "123456789a"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Long.toString(0x123456789aL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalIntFormFieldExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(optionalIntParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("optionalIntParam", "23"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(23)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringFormFieldExtractionWithDefaultValue() {
|
||||
TestRoute route = testRoute(completeWithValueToString(nameWithDefault));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("John Doe");
|
||||
|
||||
route
|
||||
.run(singleParameterUrlEncodedRequest("nameWithDefault", "paul"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("paul");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
|
||||
import akka.http.javadsl.model.*;
|
||||
import akka.http.javadsl.model.headers.Age;
|
||||
import akka.http.javadsl.model.headers.RawHeader;
|
||||
import akka.http.javadsl.server.values.*;
|
||||
|
||||
public class HeadersTest extends JUnitRouteTest {
|
||||
Header<HttpHeader> XTestHeader = Headers.byName("X-Test-Header");
|
||||
Header<Age> AgeHeader = Headers.byClass(Age.class);
|
||||
|
||||
RawHeader testHeaderInstance = RawHeader.create("X-Test-Header", "abcdef-test");
|
||||
Age ageHeaderInstance = Age.create(1000);
|
||||
|
||||
@Test
|
||||
public void testValueByName() {
|
||||
TestRoute route = testRoute(completeWithValueToString(XTestHeader.value()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required HTTP header 'X-Test-Header'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(testHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("abcdef-test");
|
||||
}
|
||||
@Test
|
||||
public void testOptionalValueByName() {
|
||||
TestRoute route = testRoute(completeWithValueToString(XTestHeader.optionalValue()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(testHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(abcdef-test)");
|
||||
}
|
||||
@Test
|
||||
public void testInstanceByName() {
|
||||
TestRoute route = testRoute(completeWithValueToString(XTestHeader.instance()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required HTTP header 'X-Test-Header'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(testHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("X-Test-Header: abcdef-test");
|
||||
}
|
||||
@Test
|
||||
public void testOptionalInstanceByName() {
|
||||
TestRoute route = testRoute(completeWithValueToString(XTestHeader.optionalInstance()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(testHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(X-Test-Header: abcdef-test)");
|
||||
}
|
||||
@Test
|
||||
public void testValueByClass() {
|
||||
TestRoute route = testRoute(completeWithValueToString(AgeHeader.value()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required HTTP header 'Age'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(ageHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("1000");
|
||||
}
|
||||
@Test
|
||||
public void testOptionalValueByClass() {
|
||||
TestRoute route = testRoute(completeWithValueToString(AgeHeader.optionalValue()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(ageHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(1000)");
|
||||
}
|
||||
@Test
|
||||
public void testInstanceByClass() {
|
||||
TestRoute route = testRoute(completeWithValueToString(AgeHeader.instance()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("Request is missing required HTTP header 'Age'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(ageHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Age: 1000");
|
||||
}
|
||||
@Test
|
||||
public void testOptionalInstanceByClass() {
|
||||
TestRoute route = testRoute(completeWithValueToString(AgeHeader.optionalInstance()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(ageHeaderInstance))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(Age: 1000)");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.server.Handler1;
|
||||
import akka.http.javadsl.server.RequestContext;
|
||||
import akka.http.javadsl.server.RequestVal;
|
||||
import akka.http.javadsl.server.RouteResult;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import akka.japi.Option;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ParametersTest extends JUnitRouteTest {
|
||||
static Parameter<String> stringParam = Parameters.stringValue("stringParam");
|
||||
static Parameter<Byte> byteParam = Parameters.byteValue("byteParam");
|
||||
static Parameter<Short> shortParam = Parameters.shortValue("shortParam");
|
||||
static Parameter<Integer> intParam = Parameters.intValue("intParam");
|
||||
static Parameter<Long> longParam = Parameters.longValue("longParam");
|
||||
static Parameter<Float> floatParam = Parameters.floatValue("floatParam");
|
||||
static Parameter<Double> doubleParam = Parameters.doubleValue("doubleParam");
|
||||
|
||||
static Parameter<Byte> hexByteParam = Parameters.hexByteValue("hexByteParam");
|
||||
static Parameter<Short> hexShortParam = Parameters.hexShortValue("hexShortParam");
|
||||
static Parameter<Integer> hexIntParam = Parameters.hexIntValue("hexIntParam");
|
||||
static Parameter<Long> hexLongParam = Parameters.hexLongValue("hexLongParam");
|
||||
|
||||
static RequestVal<String> nameWithDefault = Parameters.stringValue("nameWithDefault").withDefault("John Doe");
|
||||
static RequestVal<Option<Integer>> optionalIntParam = Parameters.intValue("optionalIntParam").optional();
|
||||
|
||||
static RequestVal<Map<String, String>> paramMap = Parameters.asMap();
|
||||
static RequestVal<Map<String, Collection<String>>> paramMultiMap = Parameters.asMultiMap();
|
||||
static RequestVal<Collection<Map.Entry<String, String>>> paramEntries = Parameters.asCollection();
|
||||
|
||||
@Test
|
||||
public void testStringParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(stringParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'stringParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?stringParam=john"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(byteParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'byteParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?byteParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'byteParam' was malformed:\n'test' is not a valid 8-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?byteParam=1000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'byteParam' was malformed:\n'1000' is not a valid 8-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?byteParam=48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(shortParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'shortParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?shortParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'shortParam' was malformed:\n'test' is not a valid 16-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?shortParam=100000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'shortParam' was malformed:\n'100000' is not a valid 16-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?shortParam=1234"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("1234");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegerParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(intParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'intParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?intParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'intParam' was malformed:\n'test' is not a valid 32-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?intParam=48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(longParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'longParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?longParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'longParam' was malformed:\n'test' is not a valid 64-bit signed integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?longParam=123456"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("123456");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(floatParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'floatParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?floatParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'floatParam' was malformed:\n'test' is not a valid 32-bit floating point value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?floatParam=48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(doubleParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'doubleParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?doubleParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'doubleParam' was malformed:\n'test' is not a valid 64-bit floating point value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?doubleParam=48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("48.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexByteParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexByteParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'hexByteParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexByteParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'hexByteParam' was malformed:\n'test' is not a valid 8-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexByteParam=1000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'hexByteParam' was malformed:\n'1000' is not a valid 8-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexByteParam=48"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Integer.toString(0x48));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexShortParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexShortParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'hexShortParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexShortParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'hexShortParam' was malformed:\n'test' is not a valid 16-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexShortParam=100000"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'hexShortParam' was malformed:\n'100000' is not a valid 16-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexShortParam=1234"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Integer.toString(0x1234));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexIntegerParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexIntParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'hexIntParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexIntParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'hexIntParam' was malformed:\n'test' is not a valid 32-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexIntParam=12345678"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Integer.toString(0x12345678));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHexLongParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(hexLongParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(404)
|
||||
.assertEntity("Request is missing required query parameter 'hexLongParam'");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexLongParam=test"))
|
||||
.assertStatusCode(400)
|
||||
.assertEntity("The query parameter 'hexLongParam' was malformed:\n'test' is not a valid 64-bit hexadecimal integer value");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?hexLongParam=123456789a"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity(Long.toString(0x123456789aL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParametersAsMapExtraction() {
|
||||
TestRoute route = testRoute(handleWith(paramMap, new Handler1<Map<String, String>>(){
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Map<String, String> paramMap) {
|
||||
ArrayList<String> keys = new ArrayList<String>(paramMap.keySet());
|
||||
Collections.sort(keys);
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append(paramMap.size()).append(": [");
|
||||
for (String key: keys)
|
||||
res.append(key).append(" -> ").append(paramMap.get(key)).append(", ");
|
||||
res.append(']');
|
||||
return ctx.complete(res.toString());
|
||||
}
|
||||
}));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("0: []");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?a=b"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("1: [a -> b, ]");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?a=b&c=d"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("2: [a -> b, c -> d, ]");
|
||||
}
|
||||
@Test
|
||||
public void testParametersAsMultiMapExtraction() {
|
||||
TestRoute route = testRoute(handleWith(paramMultiMap, new Handler1<Map<String, Collection<String>>>(){
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Map<String, Collection<String>> paramMap) {
|
||||
ArrayList<String> keys = new ArrayList<String>(paramMap.keySet());
|
||||
Collections.sort(keys);
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append(paramMap.size()).append(": [");
|
||||
for (String key: keys) {
|
||||
res.append(key).append(" -> [");
|
||||
ArrayList<String> values = new ArrayList<String>(paramMap.get(key));
|
||||
Collections.sort(values);
|
||||
for (String value: values)
|
||||
res.append(value).append(", ");
|
||||
res.append("], ");
|
||||
}
|
||||
res.append(']');
|
||||
return ctx.complete(res.toString());
|
||||
}
|
||||
}));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("0: []");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?a=b"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("1: [a -> [b, ], ]");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?a=b&c=d&a=a"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("2: [a -> [a, b, ], c -> [d, ], ]");
|
||||
}
|
||||
@Test
|
||||
public void testParametersAsCollectionExtraction() {
|
||||
TestRoute route = testRoute(handleWith(paramEntries, new Handler1<Collection<Map.Entry<String, String>>>(){
|
||||
@Override
|
||||
public RouteResult handle(RequestContext ctx, Collection<Map.Entry<String, String>> paramEntries) {
|
||||
ArrayList<Map.Entry<String, String>> entries = new ArrayList<Map.Entry<String, String>>(paramEntries);
|
||||
Collections.sort(entries, new Comparator<Map.Entry<String, String>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<String, String> e1, Map.Entry<String, String> e2) {
|
||||
int res = e1.getKey().compareTo(e2.getKey());
|
||||
return res == 0 ? e1.getValue().compareTo(e2.getValue()) : res;
|
||||
}
|
||||
});
|
||||
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append(paramEntries.size()).append(": [");
|
||||
for (Map.Entry<String, String> entry: entries)
|
||||
res.append(entry.getKey()).append(" -> ").append(entry.getValue()).append(", ");
|
||||
res.append(']');
|
||||
return ctx.complete(res.toString());
|
||||
}
|
||||
}));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("0: []");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?a=b&e=f&c=d"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("3: [a -> b, c -> d, e -> f, ]");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?a=b&e=f&c=d&a=z"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("4: [a -> b, a -> z, c -> d, e -> f, ]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalIntParameterExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(optionalIntParam));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("None");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?optionalIntParam=23"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("Some(23)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringParameterExtractionWithDefaultValue() {
|
||||
TestRoute route = testRoute(completeWithValueToString(nameWithDefault));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("John Doe");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri("/abc?nameWithDefault=paul"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("paul");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.RemoteAddress;
|
||||
import akka.http.javadsl.model.Uri;
|
||||
import akka.http.javadsl.model.headers.RawHeader;
|
||||
import akka.http.javadsl.model.headers.XForwardedFor;
|
||||
import akka.http.javadsl.server.RequestVals;
|
||||
import akka.http.javadsl.server.Unmarshallers;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RequestValTest extends JUnitRouteTest {
|
||||
@Test
|
||||
public void testSchemeExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(RequestVals.scheme()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("http");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("https://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("https");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(RequestVals.host()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("example.org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostPatternExtraction() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
completeWithValueToString(
|
||||
RequestVals.matchAndExtractHost(Pattern.compile(".*\\.([^.]*)"))));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.org")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("org");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().withUri(Uri.create("http://example.de")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("de");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientIpExtraction() {
|
||||
TestRoute route = testRoute(completeWithValueToString(RequestVals.clientIP()));
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(XForwardedFor.create(RemoteAddress.create("127.0.0.2"))))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("127.0.0.2");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(akka.http.javadsl.model.headers.RemoteAddress.create(RemoteAddress.create("127.0.0.3"))))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("127.0.0.3");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create().addHeader(RawHeader.create("X-Real-IP", "127.0.0.4")))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("127.0.0.4");
|
||||
|
||||
route
|
||||
.run(HttpRequest.create())
|
||||
.assertStatusCode(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntityAsString() {
|
||||
TestRoute route =
|
||||
testRoute(
|
||||
completeWithValueToString(RequestVals.entityAs(Unmarshallers.String()))
|
||||
);
|
||||
|
||||
HttpRequest request =
|
||||
HttpRequest.POST("/")
|
||||
.withEntity("abcdef");
|
||||
route.run(request)
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("abcdef");
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import org.scalatest.{ FreeSpec, Inside }
|
|||
import akka.http.scaladsl.unmarshalling.Unmarshaller.HexInt
|
||||
|
||||
class ParameterDirectivesSpec extends FreeSpec with GenericRoutingSpec with Inside {
|
||||
|
||||
"when used with 'as[Int]' the parameter directive should" - {
|
||||
"extract a parameter value as Int" in {
|
||||
Get("/?amount=123") ~> {
|
||||
|
|
@ -205,4 +204,23 @@ class ParameterDirectivesSpec extends FreeSpec with GenericRoutingSpec with Insi
|
|||
} ~> check { responseAs[String] === "List(3, 10)" }
|
||||
}
|
||||
}
|
||||
|
||||
"The 'parameterSeq' directive should" - {
|
||||
val completeAsList =
|
||||
parameterSeq { params ⇒
|
||||
val sorted = params.sorted
|
||||
complete(s"${sorted.size}: [${sorted.map(e ⇒ e._1 + " -> " + e._2).mkString(", ")}]")
|
||||
}
|
||||
|
||||
"extract parameters with different keys" in {
|
||||
Get("/?a=b&e=f&c=d") ~> completeAsList ~> check {
|
||||
responseAs[String] shouldEqual "3: [a -> b, c -> d, e -> f]"
|
||||
}
|
||||
}
|
||||
"extract parameters with duplicate keys" in {
|
||||
Get("/?a=b&e=f&c=d&a=z") ~> completeAsList ~> check {
|
||||
responseAs[String] shouldEqual "4: [a -> b, a -> z, c -> d, e -> f]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.impl.server
|
||||
|
||||
import akka.http.javadsl.model.headers.HttpCookie
|
||||
import akka.http.javadsl.server.values.Cookie
|
||||
import akka.http.javadsl.server.{ Directive, Directives, RequestVal }
|
||||
import akka.http.scaladsl.server.Directive1
|
||||
import akka.http.scaladsl.server.directives.CookieDirectives._
|
||||
import akka.japi.Option
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
|
||||
case class CookieImpl(name: String, domain: Option[String] = None, path: Option[String] = None) extends Cookie {
|
||||
def withDomain(domain: String): Cookie = copy(domain = Option.some(domain))
|
||||
def withPath(path: String): Cookie = copy(path = Option.some(path))
|
||||
|
||||
val value: RequestVal[String] =
|
||||
new StandaloneExtractionImpl[String] {
|
||||
def directive: Directive1[String] = cookie(name).map(_.value)
|
||||
}
|
||||
|
||||
def optionalValue(): RequestVal[Option[String]] =
|
||||
new StandaloneExtractionImpl[Option[String]] {
|
||||
def directive: Directive1[Option[String]] = optionalCookie(name).map(_.map(_.value).asJava)
|
||||
}
|
||||
|
||||
def set(value: String): Directive =
|
||||
Directives.custom(Directives.setCookie(
|
||||
HttpCookie.create(name, value, domain, path), _, _: _*))
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.impl.server
|
||||
|
||||
import akka.http.javadsl.server.RequestVal
|
||||
import akka.http.javadsl.server.values.FormField
|
||||
import akka.http.scaladsl.common.{ StrictForm, NameUnmarshallerReceptacle, NameReceptacle }
|
||||
import akka.http.scaladsl.unmarshalling._
|
||||
import akka.http.scaladsl.util.FastFuture
|
||||
import akka.japi.{ Option ⇒ JOption }
|
||||
|
||||
import scala.concurrent.{ Future, ExecutionContext }
|
||||
import scala.reflect.ClassTag
|
||||
import akka.http.scaladsl.server.directives.FormFieldDirectives
|
||||
import akka.http.scaladsl.server.{ Directives, Directive1 }
|
||||
import FormFieldDirectives._
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[http] class FormFieldImpl[T, U](receptacle: NameReceptacle[T])(
|
||||
implicit fu: FromStrictFormFieldUnmarshaller[T], tTag: ClassTag[U], conv: T ⇒ U)
|
||||
extends StandaloneExtractionImpl[U] with FormField[U] {
|
||||
import Directives._
|
||||
|
||||
def directive: Directive1[U] =
|
||||
extractMaterializer.flatMap { implicit fm ⇒
|
||||
formField(receptacle).map(conv)
|
||||
}
|
||||
|
||||
def optional: RequestVal[JOption[U]] =
|
||||
new StandaloneExtractionImpl[JOption[U]] {
|
||||
def directive: Directive1[JOption[U]] = optionalDirective
|
||||
}
|
||||
|
||||
private def optionalDirective: Directive1[JOption[U]] =
|
||||
extractMaterializer.flatMap { implicit fm ⇒
|
||||
formField(receptacle.?).map(v ⇒ JOption.fromScalaOption(v.map(conv)))
|
||||
}
|
||||
|
||||
def withDefault(defaultValue: U): RequestVal[U] =
|
||||
new StandaloneExtractionImpl[U] {
|
||||
def directive: Directive1[U] = optionalDirective.map(_.getOrElse(defaultValue))
|
||||
}
|
||||
}
|
||||
object FormFieldImpl {
|
||||
def apply[T, U](receptacle: NameReceptacle[T])(implicit fu: FromStrictFormFieldUnmarshaller[T], tTag: ClassTag[U], conv: T ⇒ U): FormField[U] =
|
||||
new FormFieldImpl[T, U](receptacle)(fu, tTag, conv)
|
||||
|
||||
def apply[T, U](receptacle: NameUnmarshallerReceptacle[T])(implicit tTag: ClassTag[U], conv: T ⇒ U): FormField[U] =
|
||||
apply(new NameReceptacle[T](receptacle.name))(StrictForm.Field.unmarshallerFromFSU(receptacle.um), tTag, conv)
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.impl.server
|
||||
|
||||
import akka.http.javadsl.model.HttpHeader
|
||||
import akka.http.javadsl.server.RequestVal
|
||||
import akka.http.javadsl.server.values.Header
|
||||
import akka.http.scaladsl
|
||||
import akka.http.scaladsl.server._
|
||||
import akka.http.scaladsl.server.directives.BasicDirectives._
|
||||
import akka.http.scaladsl.server.directives.RouteDirectives._
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
/**
|
||||
* Internal API
|
||||
*/
|
||||
private[http] object HeaderImpl {
|
||||
def apply[T <: HttpHeader](
|
||||
name: String,
|
||||
optionalDirective: ClassTag[T with scaladsl.model.HttpHeader] ⇒ Directive1[Option[T with scaladsl.model.HttpHeader]], tClassTag: ClassTag[T]): Header[T] = {
|
||||
type U = T with scaladsl.model.HttpHeader
|
||||
|
||||
// cast is safe because creation of javadsl.model.HttpHeader that are not <: scaladsl.model.HttpHeader is forbidden
|
||||
implicit def uClassTag = tClassTag.asInstanceOf[ClassTag[U]]
|
||||
|
||||
new Header[U] {
|
||||
val instanceDirective: Directive1[U] =
|
||||
optionalDirective(uClassTag).flatMap {
|
||||
case Some(v) ⇒ provide(v)
|
||||
case None ⇒ reject(MissingHeaderRejection(name))
|
||||
}
|
||||
|
||||
def instance(): RequestVal[U] =
|
||||
new StandaloneExtractionImpl[U] {
|
||||
def directive: Directive1[U] = instanceDirective
|
||||
}
|
||||
|
||||
def optionalInstance(): RequestVal[Option[U]] =
|
||||
new StandaloneExtractionImpl[Option[U]] {
|
||||
def directive: Directive1[Option[U]] = optionalDirective(uClassTag)
|
||||
}
|
||||
|
||||
def value(): RequestVal[String] =
|
||||
new StandaloneExtractionImpl[String] {
|
||||
def directive: Directive1[String] = instanceDirective.map(_.value)
|
||||
}
|
||||
|
||||
def optionalValue(): RequestVal[Option[String]] =
|
||||
new StandaloneExtractionImpl[Option[String]] {
|
||||
def directive: Directive1[Option[String]] = optionalDirective(uClassTag).map(_.map(_.value))
|
||||
}
|
||||
}.asInstanceOf[Header[T]] // undeclared covariance
|
||||
}
|
||||
}
|
||||
|
|
@ -4,22 +4,46 @@
|
|||
|
||||
package akka.http.impl.server
|
||||
|
||||
import akka.http.javadsl.server.RequestVal
|
||||
import akka.http.javadsl.server.values.Parameter
|
||||
import akka.http.scaladsl.common.{ NameUnmarshallerReceptacle, NameReceptacle }
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.unmarshalling._
|
||||
import akka.japi.{ Option ⇒ JOption }
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.reflect.ClassTag
|
||||
import akka.http.scaladsl.server.directives.{ ParameterDirectives, BasicDirectives }
|
||||
import akka.http.scaladsl.server.directives.ParameterDirectives
|
||||
import akka.http.scaladsl.server.Directive1
|
||||
import akka.http.scaladsl.server.directives.ParameterDirectives.ParamMagnet
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[http] class ParameterImpl[T: ClassTag](val underlying: ExecutionContext ⇒ ParamMagnet { type Out = Directive1[T] })
|
||||
extends StandaloneExtractionImpl[T] with Parameter[T] {
|
||||
private[http] class ParameterImpl[T, U](receptacle: NameReceptacle[T])(
|
||||
implicit fu: FromStringUnmarshaller[T], tTag: ClassTag[U], conv: T ⇒ U)
|
||||
extends StandaloneExtractionImpl[U] with Parameter[U] {
|
||||
|
||||
def directive: Directive1[T] =
|
||||
BasicDirectives.extractExecutionContext.flatMap { implicit ec ⇒
|
||||
ParameterDirectives.parameter(underlying(ec))
|
||||
import ParameterDirectives._
|
||||
def directive: Directive1[U] = parameter(receptacle).map(conv)
|
||||
|
||||
def optional: RequestVal[JOption[U]] =
|
||||
new StandaloneExtractionImpl[JOption[U]] {
|
||||
def directive: Directive1[JOption[U]] = optionalDirective
|
||||
}
|
||||
|
||||
private def optionalDirective: Directive1[JOption[U]] =
|
||||
extractMaterializer.flatMap { implicit fm ⇒
|
||||
parameter(receptacle.?).map(v ⇒ JOption.fromScalaOption(v.map(conv)))
|
||||
}
|
||||
|
||||
def withDefault(defaultValue: U): RequestVal[U] =
|
||||
new StandaloneExtractionImpl[U] {
|
||||
def directive: Directive1[U] = optionalDirective.map(_.getOrElse(defaultValue))
|
||||
}
|
||||
}
|
||||
private[http] object ParameterImpl {
|
||||
def apply[T, U](receptacle: NameReceptacle[T])(implicit fu: FromStringUnmarshaller[T], tTag: ClassTag[U], conv: T ⇒ U): Parameter[U] =
|
||||
new ParameterImpl(receptacle)(fu, tTag, conv)
|
||||
|
||||
def apply[T, U](receptacle: NameUnmarshallerReceptacle[T])(implicit tTag: ClassTag[U], conv: T ⇒ U): Parameter[U] =
|
||||
new ParameterImpl(new NameReceptacle(receptacle.name))(receptacle.um, tTag, conv)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
package akka.http.impl.server
|
||||
|
||||
import akka.http.javadsl.server.values.PathMatcher
|
||||
import akka.japi.Option
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
import akka.http.scaladsl.server.{ PathMatcher ⇒ ScalaPathMatcher }
|
||||
|
|
@ -13,4 +14,6 @@ import akka.http.scaladsl.server.{ PathMatcher ⇒ ScalaPathMatcher }
|
|||
* INTERNAL API
|
||||
*/
|
||||
private[http] class PathMatcherImpl[T: ClassTag](val matcher: ScalaPathMatcher[Tuple1[T]])
|
||||
extends ExtractionImpl[T] with PathMatcher[T]
|
||||
extends ExtractionImpl[T] with PathMatcher[T] {
|
||||
def optional: PathMatcher[Option[T]] = new PathMatcherImpl[Option[T]](matcher.?.map(Option.fromScalaOption))
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package akka.http.impl.server
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.{ ExecutionContext, Future }
|
||||
import akka.http.javadsl.{ model ⇒ jm }
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
import akka.http.scaladsl.server.{ RequestContext ⇒ ScalaRequestContext }
|
||||
|
|
@ -14,8 +14,6 @@ import akka.http.javadsl.server._
|
|||
* INTERNAL API
|
||||
*/
|
||||
private[http] final case class RequestContextImpl(underlying: ScalaRequestContext) extends RequestContext {
|
||||
import underlying.executionContext
|
||||
|
||||
// provides auto-conversion to japi.RouteResult
|
||||
import RouteResultImpl._
|
||||
|
||||
|
|
@ -25,7 +23,7 @@ private[http] final case class RequestContextImpl(underlying: ScalaRequestContex
|
|||
def completeWith(futureResult: Future[RouteResult]): RouteResult =
|
||||
futureResult.flatMap {
|
||||
case r: RouteResultImpl ⇒ r.underlying
|
||||
}
|
||||
}(executionContext)
|
||||
def complete(text: String): RouteResult = underlying.complete(text)
|
||||
def completeWithStatus(statusCode: Int): RouteResult =
|
||||
completeWithStatus(jm.StatusCodes.get(statusCode))
|
||||
|
|
@ -40,4 +38,6 @@ private[http] final case class RequestContextImpl(underlying: ScalaRequestContex
|
|||
def complete(response: jm.HttpResponse): RouteResult = underlying.complete(response.asScala)
|
||||
|
||||
def notFound(): RouteResult = underlying.reject()
|
||||
|
||||
def executionContext: ExecutionContext = underlying.executionContext
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
package akka.http.impl.server
|
||||
|
||||
import akka.http.impl.util.JavaMapping
|
||||
import akka.http.javadsl.server.values.{ PathMatcher, BasicUserCredentials }
|
||||
import akka.http.scaladsl.model.StatusCodes.Redirection
|
||||
import akka.http.scaladsl.server.util.TupleOps.Join
|
||||
|
||||
import scala.language.implicitConversions
|
||||
import scala.annotation.tailrec
|
||||
|
|
@ -13,8 +16,8 @@ import akka.http.javadsl.model.ContentType
|
|||
import akka.http.scaladsl.server.directives.{ UserCredentials, ContentTypeResolver }
|
||||
import akka.http.scaladsl.server.directives.FileAndResourceDirectives.DirectoryRenderer
|
||||
import akka.http.scaladsl.model.HttpHeader
|
||||
import akka.http.scaladsl.model.headers.CustomHeader
|
||||
import akka.http.scaladsl.server.{ Route ⇒ ScalaRoute, Directive0, Directives }
|
||||
import akka.http.scaladsl.model.headers.{ HttpCookie, CustomHeader }
|
||||
import akka.http.scaladsl.server.{ Route ⇒ ScalaRoute, Directive ⇒ ScalaDirective, PathMatcher ⇒ ScalaPathMatcher, PathMatcher1, Directive0, Directive1, Directives }
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
import akka.http.scaladsl.server
|
||||
import akka.http.javadsl.server._
|
||||
|
|
@ -26,11 +29,13 @@ import RouteStructure._
|
|||
private[http] trait ExtractionMap extends CustomHeader {
|
||||
def get[T](key: RequestVal[T]): Option[T]
|
||||
def set[T](key: RequestVal[T], value: T): ExtractionMap
|
||||
def addAll(values: Map[RequestVal[_], Any]): ExtractionMap
|
||||
}
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[http] object ExtractionMap {
|
||||
val Empty = ExtractionMap(Map.empty)
|
||||
implicit def apply(map: Map[RequestVal[_], Any]): ExtractionMap =
|
||||
new ExtractionMap {
|
||||
def get[T](key: RequestVal[T]): Option[T] =
|
||||
|
|
@ -39,6 +44,9 @@ private[http] object ExtractionMap {
|
|||
def set[T](key: RequestVal[T], value: T): ExtractionMap =
|
||||
ExtractionMap(map.updated(key, value))
|
||||
|
||||
def addAll(values: Map[RequestVal[_], Any]): ExtractionMap =
|
||||
ExtractionMap(map ++ values)
|
||||
|
||||
// CustomHeader methods
|
||||
override def suppressRendering: Boolean = true
|
||||
def name(): String = "ExtractedValues"
|
||||
|
|
@ -50,99 +58,146 @@ private[http] object ExtractionMap {
|
|||
* INTERNAL API
|
||||
*/
|
||||
private[http] object RouteImplementation extends Directives with server.RouteConcatenation {
|
||||
def apply(route: Route): ScalaRoute = route match {
|
||||
case RouteAlternatives(children) ⇒
|
||||
val converted = children.map(RouteImplementation.apply)
|
||||
converted.reduce(_ ~ _)
|
||||
case RawPathPrefix(elements, children) ⇒
|
||||
val inner = apply(RouteAlternatives(children))
|
||||
def apply(route: Route): ScalaRoute = {
|
||||
def directiveFor(route: DirectiveRoute): Directive0 = route match {
|
||||
case RouteAlternatives() ⇒ ScalaDirective.Empty
|
||||
case RawPathPrefix(elements) ⇒ pathMatcherDirective[String](elements, rawPathPrefix)
|
||||
case RawPathPrefixTest(elements) ⇒ pathMatcherDirective[String](elements, rawPathPrefixTest)
|
||||
case PathSuffix(elements) ⇒ pathMatcherDirective[String](elements, pathSuffix)
|
||||
case PathSuffixTest(elements) ⇒ pathMatcherDirective[String](elements, pathSuffixTest)
|
||||
case RedirectToTrailingSlashIfMissing(code) ⇒ redirectToTrailingSlashIfMissing(code.asScala.asInstanceOf[Redirection])
|
||||
case RedirectToNoTrailingSlashIfPresent(code) ⇒ redirectToNoTrailingSlashIfPresent(code.asScala.asInstanceOf[Redirection])
|
||||
|
||||
def one[T](matcher: PathMatcher[T]): Directive0 =
|
||||
rawPathPrefix(matcher.asInstanceOf[PathMatcherImpl[T]].matcher) flatMap { value ⇒
|
||||
addExtraction(matcher, value)
|
||||
case MethodFilter(m) ⇒ method(m.asScala)
|
||||
case Extract(extractions) ⇒
|
||||
extractRequestContext.flatMap { ctx ⇒
|
||||
extractions.map { e ⇒
|
||||
e.directive.flatMap(addExtraction(e.asInstanceOf[RequestVal[Any]], _))
|
||||
}.reduce(_ & _)
|
||||
}
|
||||
elements.map(one(_)).reduce(_ & _).apply(inner)
|
||||
|
||||
case GetFromResource(path, contentType, classLoader) ⇒
|
||||
getFromResource(path, contentType.asScala, classLoader)
|
||||
case GetFromResourceDirectory(path, classLoader, resolver) ⇒
|
||||
getFromResourceDirectory(path, classLoader)(scalaResolver(resolver))
|
||||
case GetFromFile(file, contentType) ⇒
|
||||
getFromFile(file, contentType.asScala)
|
||||
case GetFromDirectory(directory, true, resolver) ⇒
|
||||
extractExecutionContext { implicit ec ⇒
|
||||
getFromBrowseableDirectory(directory.getPath)(DirectoryRenderer.defaultDirectoryRenderer, scalaResolver(resolver))
|
||||
}
|
||||
case FileAndResourceRouteWithDefaultResolver(constructor) ⇒
|
||||
RouteImplementation(constructor(new directives.ContentTypeResolver {
|
||||
def resolve(fileName: String): ContentType = ContentTypeResolver.Default(fileName)
|
||||
}))
|
||||
case BasicAuthentication(authenticator) ⇒
|
||||
authenticateBasicAsync(authenticator.realm, { creds ⇒
|
||||
val javaCreds =
|
||||
creds match {
|
||||
case UserCredentials.Missing ⇒
|
||||
new BasicUserCredentials {
|
||||
def available: Boolean = false
|
||||
def userName: String = throw new IllegalStateException("Credentials missing")
|
||||
def verifySecret(secret: String): Boolean = throw new IllegalStateException("Credentials missing")
|
||||
}
|
||||
case p @ UserCredentials.Provided(name) ⇒
|
||||
new BasicUserCredentials {
|
||||
def available: Boolean = true
|
||||
def userName: String = name
|
||||
def verifySecret(secret: String): Boolean = p.verifySecret(secret)
|
||||
}
|
||||
}
|
||||
|
||||
case MethodFilter(m, children) ⇒
|
||||
val inner = apply(RouteAlternatives(children))
|
||||
method(m.asScala).apply(inner)
|
||||
authenticator.authenticate(javaCreds)
|
||||
}).flatMap { user ⇒
|
||||
addExtraction(authenticator.asInstanceOf[RequestVal[Any]], user)
|
||||
}
|
||||
|
||||
case Extract(extractions, children) ⇒
|
||||
val inner = apply(RouteAlternatives(children))
|
||||
extractRequestContext.flatMap { ctx ⇒
|
||||
extractions.map { e ⇒
|
||||
e.directive.flatMap(addExtraction(e.asInstanceOf[RequestVal[Any]], _))
|
||||
}.reduce(_ & _)
|
||||
}.apply(inner)
|
||||
case EncodeResponse(coders) ⇒
|
||||
val scalaCoders = coders.map(_._underlyingScalaCoder())
|
||||
encodeResponseWith(scalaCoders.head, scalaCoders.tail: _*)
|
||||
|
||||
case BasicAuthentication(authenticator, children) ⇒
|
||||
val inner = apply(RouteAlternatives(children))
|
||||
authenticateBasicAsync(authenticator.realm, { creds ⇒
|
||||
val javaCreds =
|
||||
creds match {
|
||||
case UserCredentials.Missing ⇒
|
||||
new BasicUserCredentials {
|
||||
def available: Boolean = false
|
||||
def userName: String = throw new IllegalStateException("Credentials missing")
|
||||
def verifySecret(secret: String): Boolean = throw new IllegalStateException("Credentials missing")
|
||||
}
|
||||
case p @ UserCredentials.Provided(name) ⇒
|
||||
new BasicUserCredentials {
|
||||
def available: Boolean = true
|
||||
def userName: String = name
|
||||
def verifySecret(secret: String): Boolean = p.verifySecret(secret)
|
||||
}
|
||||
}
|
||||
case DecodeRequest(coders) ⇒ decodeRequestWith(coders.map(_._underlyingScalaCoder()): _*)
|
||||
case Conditional(eTag, lastModified) ⇒ conditional(eTag.map(_.asScala), lastModified.map(_.asScala))
|
||||
case h: HostFilter ⇒ host(h.filter _)
|
||||
case SchemeFilter(schemeName) ⇒ scheme(schemeName)
|
||||
|
||||
authenticator.authenticate(javaCreds)
|
||||
}).flatMap { user ⇒
|
||||
addExtraction(authenticator.asInstanceOf[RequestVal[Any]], user)
|
||||
}.apply(inner)
|
||||
case HandleExceptions(handler) ⇒
|
||||
val pf: akka.http.scaladsl.server.ExceptionHandler = akka.http.scaladsl.server.ExceptionHandler {
|
||||
case e: RuntimeException ⇒ apply(handler.handle(e))
|
||||
}
|
||||
handleExceptions(pf)
|
||||
|
||||
case EncodeResponse(coders, children) ⇒
|
||||
val scalaCoders = coders.map(_._underlyingScalaCoder())
|
||||
encodeResponseWith(scalaCoders.head, scalaCoders.tail: _*).apply(apply(RouteAlternatives(children)))
|
||||
case Validated(isValid, errorMsg) ⇒ validate(isValid, errorMsg)
|
||||
case RangeSupport() ⇒ withRangeSupport
|
||||
case SetCookie(cookie) ⇒ setCookie(cookie.asScala)
|
||||
case DeleteCookie(name, domain, path) ⇒ deleteCookie(HttpCookie(name, domain = domain, path = path, value = "deleted"))
|
||||
}
|
||||
|
||||
case Conditional(eTag, lastModified, children) ⇒
|
||||
conditional(eTag.asScala, lastModified.asScala).apply(apply(RouteAlternatives(children)))
|
||||
route match {
|
||||
case route: DirectiveRoute ⇒ directiveFor(route).apply(fromAlternatives(route.children))
|
||||
case GetFromResource(path, contentType, classLoader) ⇒ getFromResource(path, contentType.asScala, classLoader)
|
||||
case GetFromResourceDirectory(path, classLoader, resolver) ⇒ getFromResourceDirectory(path, classLoader)(scalaResolver(resolver))
|
||||
case GetFromFile(file, contentType) ⇒ getFromFile(file, contentType.asScala)
|
||||
case GetFromDirectory(directory, true, resolver) ⇒
|
||||
extractExecutionContext { implicit ec ⇒
|
||||
getFromBrowseableDirectory(directory.getPath)(DirectoryRenderer.defaultDirectoryRenderer, scalaResolver(resolver))
|
||||
}
|
||||
case FileAndResourceRouteWithDefaultResolver(constructor) ⇒
|
||||
RouteImplementation(constructor(new directives.ContentTypeResolver {
|
||||
def resolve(fileName: String): ContentType = ContentTypeResolver.Default(fileName)
|
||||
}))
|
||||
|
||||
case HandleExceptions(handler, children) ⇒
|
||||
val pf: akka.http.scaladsl.server.ExceptionHandler = akka.http.scaladsl.server.ExceptionHandler {
|
||||
case e: RuntimeException ⇒ apply(handler.handle(e))
|
||||
}
|
||||
handleExceptions(pf).apply(apply(RouteAlternatives(children)))
|
||||
case HandleWebsocketMessages(handler) ⇒ handleWebsocketMessages(JavaMapping.toScala(handler))
|
||||
case Redirect(uri, code) ⇒ redirect(uri.asScala, code.asScala.asInstanceOf[Redirection]) // guarded by require in Redirect
|
||||
|
||||
case o: OpaqueRoute ⇒
|
||||
(ctx ⇒ o.handle(new RequestContextImpl(ctx)).asInstanceOf[RouteResultImpl].underlying)
|
||||
case dyn: DynamicDirectiveRoute1[t1Type] ⇒
|
||||
def runToRoute(t1: t1Type): ScalaRoute =
|
||||
apply(dyn.createDirective(t1).route(dyn.innerRoute, dyn.moreInnerRoutes: _*))
|
||||
|
||||
case p: Product ⇒ extractExecutionContext { implicit ec ⇒ complete(500, s"Not implemented: ${p.productPrefix}") }
|
||||
requestValToDirective(dyn.value1)(runToRoute)
|
||||
|
||||
case dyn: DynamicDirectiveRoute2[t1Type, t2Type] ⇒
|
||||
def runToRoute(t1: t1Type, t2: t2Type): ScalaRoute =
|
||||
apply(dyn.createDirective(t1, t2).route(dyn.innerRoute, dyn.moreInnerRoutes: _*))
|
||||
|
||||
(requestValToDirective(dyn.value1) & requestValToDirective(dyn.value2))(runToRoute)
|
||||
|
||||
case o: OpaqueRoute ⇒ (ctx ⇒ o.handle(new RequestContextImpl(ctx)).asInstanceOf[RouteResultImpl].underlying)
|
||||
case p: Product ⇒ extractExecutionContext { implicit ec ⇒ complete(500, s"Not implemented: ${p.productPrefix}") }
|
||||
}
|
||||
}
|
||||
def pathMatcherDirective[T](matchers: immutable.Seq[PathMatcher[_]],
|
||||
directive: PathMatcher1[T] ⇒ Directive1[T] // this type is too specific and only a placeholder for a proper polymorphic function
|
||||
): Directive0 = {
|
||||
// Concatenating PathMatchers is a bit complicated as we don't want to build up a tuple
|
||||
// but something which we can later split all the separate values and add them to the
|
||||
// ExtractionMap.
|
||||
//
|
||||
// This is achieved by providing a specialized `Join` instance to use with PathMatcher
|
||||
// which provides the desired behavior.
|
||||
|
||||
type ValMap = Tuple1[Map[RequestVal[_], Any]]
|
||||
object AddToMapJoin extends Join[ValMap, ValMap] {
|
||||
type Out = ValMap
|
||||
def apply(prefix: ValMap, suffix: ValMap): AddToMapJoin.Out =
|
||||
Tuple1(prefix._1 ++ suffix._1)
|
||||
}
|
||||
def toScala(matcher: PathMatcher[_]): ScalaPathMatcher[ValMap] =
|
||||
matcher.asInstanceOf[PathMatcherImpl[_]].matcher.transform(_.map(v ⇒ Tuple1(Map(matcher -> v._1))))
|
||||
def addExtractions(valMap: T): Directive0 = transformExtractionMap(_.addAll(valMap.asInstanceOf[Map[RequestVal[_], Any]]))
|
||||
val reduced: ScalaPathMatcher[ValMap] = matchers.map(toScala).reduce(_.~(_)(AddToMapJoin))
|
||||
directive(reduced.asInstanceOf[PathMatcher1[T]]).flatMap(addExtractions)
|
||||
}
|
||||
|
||||
def addExtraction[T](key: RequestVal[T], value: T): Directive0 = {
|
||||
@tailrec def addToExtractionMap(headers: immutable.Seq[HttpHeader], prefix: Vector[HttpHeader] = Vector.empty): immutable.Seq[HttpHeader] =
|
||||
def fromAlternatives(alternatives: Seq[Route]): ScalaRoute =
|
||||
alternatives.map(RouteImplementation.apply).reduce(_ ~ _)
|
||||
|
||||
def addExtraction[T](key: RequestVal[T], value: T): Directive0 =
|
||||
transformExtractionMap(_.set(key, value))
|
||||
|
||||
def transformExtractionMap(f: ExtractionMap ⇒ ExtractionMap): Directive0 = {
|
||||
@tailrec def updateExtractionMap(headers: immutable.Seq[HttpHeader], prefix: Vector[HttpHeader] = Vector.empty): immutable.Seq[HttpHeader] =
|
||||
headers match {
|
||||
case (m: ExtractionMap) +: rest ⇒ m.set(key, value) +: (prefix ++ rest)
|
||||
case other +: rest ⇒ addToExtractionMap(rest, prefix :+ other)
|
||||
case Nil ⇒ ExtractionMap(Map(key -> value)) +: prefix
|
||||
case (m: ExtractionMap) +: rest ⇒ f(m) +: (prefix ++ rest)
|
||||
case other +: rest ⇒ updateExtractionMap(rest, prefix :+ other)
|
||||
case Nil ⇒ f(ExtractionMap.Empty) +: prefix
|
||||
}
|
||||
mapRequest(_.mapHeaders(addToExtractionMap(_)))
|
||||
mapRequest(_.mapHeaders(updateExtractionMap(_)))
|
||||
}
|
||||
|
||||
private def scalaResolver(resolver: directives.ContentTypeResolver): ContentTypeResolver =
|
||||
ContentTypeResolver(f ⇒ resolver.resolve(f).asScala)
|
||||
|
||||
def requestValToDirective[T](value: RequestVal[T]): Directive1[T] =
|
||||
value match {
|
||||
case s: StandaloneExtractionImpl[_] ⇒ s.directive
|
||||
case v: RequestVal[_] ⇒ extract(ctx ⇒ v.get(new RequestContextImpl(ctx)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@
|
|||
package akka.http.impl.server
|
||||
|
||||
import java.io.File
|
||||
import akka.http.javadsl.model.ws.Message
|
||||
import akka.http.javadsl.server.values.{ PathMatcher, HttpBasicAuthenticator }
|
||||
import akka.stream.javadsl.Flow
|
||||
|
||||
import scala.language.existentials
|
||||
import scala.collection.immutable
|
||||
import akka.http.javadsl.model.{ DateTime, ContentType, HttpMethod }
|
||||
import akka.http.javadsl.model.headers.EntityTag
|
||||
import akka.http.javadsl.model._
|
||||
import akka.http.javadsl.model.headers.{ HttpCookie, EntityTag }
|
||||
import akka.http.javadsl.server.directives.ContentTypeResolver
|
||||
import akka.http.javadsl.server._
|
||||
|
||||
|
|
@ -19,13 +21,15 @@ import akka.http.javadsl.server._
|
|||
*/
|
||||
private[http] object RouteStructure {
|
||||
trait DirectiveRoute extends Route {
|
||||
def children: immutable.Seq[Route]
|
||||
def innerRoute: Route
|
||||
def moreInnerRoutes: immutable.Seq[Route]
|
||||
|
||||
def children: immutable.Seq[Route] = innerRoute +: moreInnerRoutes
|
||||
|
||||
require(children.nonEmpty)
|
||||
}
|
||||
case class RouteAlternatives(children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
case class MethodFilter(method: HttpMethod, children: immutable.Seq[Route]) extends DirectiveRoute {
|
||||
case class RouteAlternatives()(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class MethodFilter(method: HttpMethod)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute {
|
||||
def filter(ctx: RequestContext): Boolean = ctx.request.method == method
|
||||
}
|
||||
|
||||
|
|
@ -34,15 +38,54 @@ private[http] object RouteStructure {
|
|||
case class GetFromResourceDirectory(resourceDirectory: String, classLoader: ClassLoader, resolver: ContentTypeResolver) extends Route
|
||||
case class GetFromFile(file: File, contentType: ContentType) extends Route
|
||||
case class GetFromDirectory(directory: File, browseable: Boolean, resolver: ContentTypeResolver) extends Route
|
||||
case class Redirect(uri: Uri, redirectionType: StatusCode) extends Route {
|
||||
require(redirectionType.isRedirection, s"`redirectionType` must be a redirection status code but was $redirectionType")
|
||||
}
|
||||
|
||||
case class RawPathPrefix(pathElements: immutable.Seq[PathMatcher[_]], children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class Extract(extractions: Seq[StandaloneExtractionImpl[_]], children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class BasicAuthentication(authenticator: HttpBasicAuthenticator[_], children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class EncodeResponse(coders: immutable.Seq[Coder], children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class PathSuffix(pathElements: immutable.Seq[PathMatcher[_]])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class PathSuffixTest(pathElements: immutable.Seq[PathMatcher[_]])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class RawPathPrefix(pathElements: immutable.Seq[PathMatcher[_]])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class RawPathPrefixTest(pathElements: immutable.Seq[PathMatcher[_]])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class RedirectToTrailingSlashIfMissing(redirectionType: StatusCode)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute {
|
||||
require(redirectionType.isRedirection, s"`redirectionType` must be a redirection status code but was $redirectionType")
|
||||
}
|
||||
case class RedirectToNoTrailingSlashIfPresent(redirectionType: StatusCode)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute {
|
||||
require(redirectionType.isRedirection, s"`redirectionType` must be a redirection status code but was $redirectionType")
|
||||
}
|
||||
case class Extract(extractions: Seq[StandaloneExtractionImpl[_]])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class BasicAuthentication(authenticator: HttpBasicAuthenticator[_])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class EncodeResponse(coders: immutable.Seq[Coder])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class DecodeRequest(coders: immutable.Seq[Coder])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
case class Conditional(entityTag: EntityTag, lastModified: DateTime, children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class Conditional(entityTag: Option[EntityTag] = None, lastModified: Option[DateTime] = None)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute {
|
||||
require(entityTag.isDefined || lastModified.isDefined)
|
||||
}
|
||||
|
||||
case class HandleExceptions(handler: ExceptionHandler, children: immutable.Seq[Route]) extends DirectiveRoute
|
||||
abstract class DynamicDirectiveRoute1[T1](val value1: RequestVal[T1])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends Route {
|
||||
def createDirective(t1: T1): Directive
|
||||
}
|
||||
abstract class DynamicDirectiveRoute2[T1, T2](val value1: RequestVal[T1], val value2: RequestVal[T2])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends Route {
|
||||
def createDirective(t1: T1, t2: T2): Directive
|
||||
}
|
||||
case class Validated(isValid: Boolean, errorMsg: String)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
case class HandleExceptions(handler: ExceptionHandler)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
sealed abstract class HostFilter extends DirectiveRoute {
|
||||
def filter(hostName: String): Boolean
|
||||
}
|
||||
case class HostNameFilter(hostWhiteList: immutable.Seq[String])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends HostFilter {
|
||||
def filter(hostName: String): Boolean = hostWhiteList.contains(hostName)
|
||||
}
|
||||
abstract class GenericHostFilter(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends HostFilter
|
||||
case class SchemeFilter(scheme: String)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
case class RangeSupport()(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
case class HandleWebsocketMessages(handler: Flow[Message, Message, Any]) extends Route
|
||||
|
||||
case class SetCookie(cookie: HttpCookie)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
case class DeleteCookie(name: String, domain: Option[String], path: Option[String])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute
|
||||
|
||||
abstract class OpaqueRoute(extractions: RequestVal[_]*) extends Route {
|
||||
def handle(ctx: RequestContext): RouteResult
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ import akka.http.scaladsl.server._
|
|||
private[http] abstract class StandaloneExtractionImpl[T: ClassTag] extends ExtractionImpl[T] with RequestVal[T] {
|
||||
def directive: Directive1[T]
|
||||
}
|
||||
private[http] object StandaloneExtractionImpl {
|
||||
def apply[T: ClassTag](extractionDirective: Directive1[T]): RequestVal[T] =
|
||||
new StandaloneExtractionImpl[T] {
|
||||
def directive: Directive1[T] = extractionDirective
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ import scala.collection.immutable
|
|||
import scala.annotation.varargs
|
||||
import akka.http.javadsl.model.HttpMethods
|
||||
|
||||
// FIXME: add support for the remaining directives, see #16436
|
||||
abstract class AllDirectives extends PathDirectives
|
||||
abstract class AllDirectives extends WebsocketDirectives
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -19,8 +18,8 @@ object Directives extends AllDirectives {
|
|||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[http] def custom(f: immutable.Seq[Route] ⇒ Route): Directive =
|
||||
private[http] def custom(f: (Route, immutable.Seq[Route]) ⇒ Route): Directive =
|
||||
new AbstractDirective {
|
||||
def createRoute(first: Route, others: Array[Route]): Route = f(first +: others.toVector)
|
||||
def createRoute(first: Route, others: Array[Route]): Route = f(first, others.toList)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package akka.http.javadsl.server
|
|||
import akka.http.javadsl.model._
|
||||
import akka.util.ByteString
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.{ ExecutionContext, Future }
|
||||
|
||||
/**
|
||||
* The RequestContext represents the state of the request while it is routed through
|
||||
|
|
@ -61,5 +61,8 @@ trait RequestContext {
|
|||
*/
|
||||
def notFound(): RouteResult
|
||||
|
||||
/** Returns the ExecutionContext of this RequestContext */
|
||||
def executionContext(): ExecutionContext
|
||||
|
||||
// FIXME: provide proper support for rejections, see #16438
|
||||
}
|
||||
|
|
@ -4,13 +4,14 @@
|
|||
|
||||
package akka.http.javadsl.server
|
||||
|
||||
import java.util.regex.Pattern
|
||||
import java.{ util ⇒ ju }
|
||||
import scala.concurrent.Future
|
||||
import scala.reflect.ClassTag
|
||||
import akka.http.javadsl.model.HttpMethod
|
||||
import akka.http.javadsl.model.{ RemoteAddress, HttpMethod }
|
||||
import akka.http.scaladsl.server
|
||||
import akka.http.scaladsl.server._
|
||||
import akka.http.scaladsl.server.directives.{ RouteDirectives, BasicDirectives }
|
||||
import akka.http.scaladsl.server.directives._
|
||||
import akka.http.impl.server.{ UnmarshallerImpl, ExtractingStandaloneExtractionImpl, RequestContextImpl, StandaloneExtractionImpl }
|
||||
import akka.http.scaladsl.util.FastFuture
|
||||
import akka.http.impl.util.JavaMapping.Implicits._
|
||||
|
|
@ -38,6 +39,58 @@ object RequestVals {
|
|||
def extract(ctx: server.RequestContext): Future[HttpMethod] = FastFuture.successful(ctx.request.method.asJava)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the scheme used for this request.
|
||||
*/
|
||||
def requestContext: RequestVal[RequestContext] =
|
||||
new StandaloneExtractionImpl[RequestContext] {
|
||||
def directive: Directive1[RequestContext] = BasicDirectives.extractRequestContext.map(RequestContextImpl(_): RequestContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the unmatched path of the request context.
|
||||
*/
|
||||
def unmatchedPath: RequestVal[String] =
|
||||
new ExtractingStandaloneExtractionImpl[String] {
|
||||
def extract(ctx: server.RequestContext): Future[String] = FastFuture.successful(ctx.unmatchedPath.toString)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the scheme used for this request.
|
||||
*/
|
||||
def scheme: RequestVal[String] =
|
||||
new StandaloneExtractionImpl[String] {
|
||||
def directive: Directive1[String] = SchemeDirectives.extractScheme
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the host name this request targeted.
|
||||
*/
|
||||
def host: RequestVal[String] =
|
||||
new StandaloneExtractionImpl[String] {
|
||||
def directive: Directive1[String] = HostDirectives.extractHost
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the host name this request targeted.
|
||||
*/
|
||||
def matchAndExtractHost(regex: Pattern): RequestVal[String] =
|
||||
new StandaloneExtractionImpl[String] {
|
||||
def directive: Directive1[String] = HostDirectives.host(regex.pattern().r)
|
||||
}
|
||||
|
||||
/**
|
||||
* Directive extracting the IP of the client from either the X-Forwarded-For, Remote-Address or X-Real-IP header
|
||||
* (in that order of priority).
|
||||
*
|
||||
* TODO: add link to the configuration entry that would add a remote-address header
|
||||
*/
|
||||
def clientIP(): RequestVal[RemoteAddress] =
|
||||
new StandaloneExtractionImpl[RemoteAddress] {
|
||||
def directive: Directive1[RemoteAddress] =
|
||||
MiscDirectives.extractClientIP.map(x ⇒ x: RemoteAddress) // missing covariance of Directive
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [[RequestVal]] given a [[ju.Map]] and a [[RequestVal]] that represents the key.
|
||||
* The new RequestVal represents the existing value as looked up in the map. If the key doesn't
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
|
||||
import akka.http.impl.server.UnmarshallerImpl
|
||||
import akka.http.scaladsl.unmarshalling.{ FromMessageUnmarshaller, PredefinedFromEntityUnmarshallers }
|
||||
|
||||
object Unmarshallers {
|
||||
def String: Unmarshaller[String] =
|
||||
new UnmarshallerImpl[String]({ (ec, mat) ⇒
|
||||
implicit val _ = mat
|
||||
implicitly[FromMessageUnmarshaller[String]]
|
||||
})
|
||||
}
|
||||
|
|
@ -5,20 +5,22 @@
|
|||
package akka.http.javadsl.server.directives
|
||||
|
||||
import scala.annotation.varargs
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.{ ParameterizedType, Method }
|
||||
|
||||
import akka.http.javadsl.model.{ StatusCode, HttpResponse }
|
||||
import akka.http.javadsl.server._
|
||||
import akka.http.impl.server.RouteStructure._
|
||||
import akka.http.impl.server._
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
abstract class BasicDirectives {
|
||||
/**
|
||||
* Tries the given routes in sequence until the first one matches.
|
||||
*/
|
||||
@varargs
|
||||
def route(route: Route, others: Route*): Route =
|
||||
RouteAlternatives(route +: others.toVector)
|
||||
def route(innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteAlternatives()(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* A route that completes the request with a static text
|
||||
|
|
@ -64,7 +66,7 @@ abstract class BasicDirectives {
|
|||
*/
|
||||
@varargs
|
||||
def extractHere(extractions: RequestVal[_]*): Directive =
|
||||
Directives.custom(Extract(extractions.map(_.asInstanceOf[StandaloneExtractionImpl[_ <: AnyRef]]), _))
|
||||
Directives.custom(Extract(extractions.map(_.asInstanceOf[StandaloneExtractionImpl[_ <: AnyRef]])))
|
||||
|
||||
/**
|
||||
* A route that handles the request with the given opaque handler. Specify a set of extractions
|
||||
|
|
@ -168,22 +170,35 @@ abstract class BasicDirectives {
|
|||
res
|
||||
}
|
||||
def returnTypeMatches(method: Method): Boolean =
|
||||
method.getReturnType == classOf[RouteResult]
|
||||
method.getReturnType == classOf[RouteResult] || returnsFuture(method)
|
||||
|
||||
def returnsFuture(method: Method): Boolean =
|
||||
method.getReturnType == classOf[Future[_]] &&
|
||||
method.getGenericReturnType.isInstanceOf[ParameterizedType] &&
|
||||
method.getGenericReturnType.asInstanceOf[ParameterizedType].getActualTypeArguments()(0) == classOf[RouteResult]
|
||||
|
||||
/** Makes sure both RouteResult and Future[RouteResult] are acceptable result types. */
|
||||
def adaptResult(method: Method): (RequestContext, AnyRef) ⇒ RouteResult =
|
||||
if (returnsFuture(method)) (ctx, v) ⇒ ctx.completeWith(v.asInstanceOf[Future[RouteResult]])
|
||||
else (_, v) ⇒ v.asInstanceOf[RouteResult]
|
||||
|
||||
val IdentityAdaptor: (RequestContext, Seq[Any]) ⇒ Seq[Any] = (_, ps) ⇒ ps
|
||||
def methodInvocator(method: Method, adaptParams: (RequestContext, Seq[Any]) ⇒ Seq[Any]): (RequestContext, Seq[Any]) ⇒ RouteResult = {
|
||||
val resultAdaptor = adaptResult(method)
|
||||
if (!method.isAccessible) method.setAccessible(true)
|
||||
if (adaptParams == IdentityAdaptor)
|
||||
(ctx, params) ⇒ resultAdaptor(ctx, method.invoke(instance, params.toArray.asInstanceOf[Array[AnyRef]]: _*))
|
||||
else
|
||||
(ctx, params) ⇒ resultAdaptor(ctx, method.invoke(instance, adaptParams(ctx, params).toArray.asInstanceOf[Array[AnyRef]]: _*))
|
||||
}
|
||||
|
||||
object ParameterTypes {
|
||||
def unapply(method: Method): Option[List[Class[_]]] = Some(method.getParameterTypes.toList)
|
||||
}
|
||||
|
||||
methods.filter(returnTypeMatches).collectFirst {
|
||||
case method @ ParameterTypes(RequestContextClass :: rest) if paramsMatch(rest) ⇒ {
|
||||
if (!method.isAccessible) method.setAccessible(true) // FIXME: test what happens if this fails
|
||||
(ctx: RequestContext, params: Seq[Any]) ⇒ method.invoke(instance, (ctx +: params).toArray.asInstanceOf[Array[AnyRef]]: _*).asInstanceOf[RouteResult]
|
||||
}
|
||||
|
||||
case method @ ParameterTypes(rest) if paramsMatch(rest) ⇒ {
|
||||
if (!method.isAccessible) method.setAccessible(true)
|
||||
(ctx: RequestContext, params: Seq[Any]) ⇒ method.invoke(instance, params.toArray.asInstanceOf[Array[AnyRef]]: _*).asInstanceOf[RouteResult]
|
||||
}
|
||||
case method @ ParameterTypes(RequestContextClass :: rest) if paramsMatch(rest) ⇒ methodInvocator(method, _ +: _)
|
||||
case method @ ParameterTypes(rest) if paramsMatch(rest) ⇒ methodInvocator(method, IdentityAdaptor)
|
||||
}.getOrElse(throw new RuntimeException("No suitable method found"))
|
||||
}
|
||||
def lookupMethod() = {
|
||||
|
|
|
|||
|
|
@ -14,12 +14,46 @@ import scala.annotation.varargs
|
|||
abstract class CacheConditionDirectives extends BasicDirectives {
|
||||
/**
|
||||
* Wraps its inner route with support for Conditional Requests as defined
|
||||
* by tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26
|
||||
* by http://tools.ietf.org/html/rfc7232
|
||||
*
|
||||
* In particular the algorithm defined by tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-6
|
||||
* 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.
|
||||
*/
|
||||
@varargs
|
||||
def conditional(entityTag: EntityTag, lastModified: DateTime, innerRoutes: Route*): Route =
|
||||
RouteStructure.Conditional(entityTag, lastModified, innerRoutes.toVector)
|
||||
def conditional(entityTag: EntityTag, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.Conditional(entityTag = Some(entityTag))(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@varargs
|
||||
def conditional(lastModified: DateTime, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.Conditional(lastModified = Some(lastModified))(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@varargs
|
||||
def conditional(entityTag: EntityTag, lastModified: DateTime, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.Conditional(Some(entityTag), Some(lastModified))(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,18 @@
|
|||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives
|
||||
package akka.http.javadsl.server
|
||||
package directives
|
||||
|
||||
import akka.http.javadsl.server.Directive
|
||||
import akka.http.javadsl.server.Directives
|
||||
import akka.http.javadsl.server.Route
|
||||
import akka.http.scaladsl.coding.Decoder
|
||||
import akka.http.scaladsl.server._
|
||||
|
||||
import scala.annotation.varargs
|
||||
import akka.http.scaladsl
|
||||
import akka.http.impl.server.RouteStructure
|
||||
import akka.http.javadsl.server.{ Coder, Directive, Directives, Route }
|
||||
|
||||
abstract class CodingDirectives extends CacheConditionDirectives {
|
||||
/**
|
||||
|
|
@ -14,9 +21,8 @@ abstract class CodingDirectives extends CacheConditionDirectives {
|
|||
* using one of the predefined coders, `Gzip`, `Deflate`, or `NoCoding` depending on
|
||||
* a potential [[akka.http.javadsl.model.headers.AcceptEncoding]] header from the client.
|
||||
*/
|
||||
@varargs def encodeResponse(innerRoutes: Route*): Route =
|
||||
// FIXME: make sure this list stays synchronized with the Scala one
|
||||
RouteStructure.EncodeResponse(List(Coder.NoCoding, Coder.Gzip, Coder.Deflate), innerRoutes.toVector)
|
||||
@varargs def encodeResponse(innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.EncodeResponse(CodingDirectives._DefaultCodersToEncodeResponse)(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* A directive that Wraps its inner routes with encoding support.
|
||||
|
|
@ -27,5 +33,42 @@ abstract class CodingDirectives extends CacheConditionDirectives {
|
|||
* will be respected (or otherwise, if no matching .
|
||||
*/
|
||||
@varargs def encodeResponse(coders: Coder*): Directive =
|
||||
Directives.custom(RouteStructure.EncodeResponse(coders.toList, _))
|
||||
Directives.custom(RouteStructure.EncodeResponse(coders.toList))
|
||||
|
||||
/**
|
||||
* Decodes the incoming request using the given Decoder.
|
||||
* If the request encoding doesn't match the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
||||
*/
|
||||
@varargs def decodeRequestWith(decoder: Coder, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.DecodeRequest(decoder :: Nil)(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* Decodes the incoming request if it is encoded with one of the given
|
||||
* encoders. If the request encoding doesn't match one of the given encoders
|
||||
* the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
||||
* If no decoders are given the default encoders (``Gzip``, ``Deflate``, ``NoCoding``) are used.
|
||||
*/
|
||||
@varargs def decodeRequestWith(decoders: Coder*): Directive =
|
||||
Directives.custom(RouteStructure.DecodeRequest(decoders.toList))
|
||||
|
||||
/**
|
||||
* Decompresses the incoming request if it is ``gzip`` or ``deflate`` compressed.
|
||||
* Uncompressed requests are passed through untouched.
|
||||
* If the request encoded with another encoding the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
||||
*/
|
||||
@varargs def decodeRequest(innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.DecodeRequest(CodingDirectives._DefaultCodersToDecodeRequest)(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal API
|
||||
*/
|
||||
private[http] object CodingDirectives {
|
||||
private[http] val _DefaultCodersToEncodeResponse =
|
||||
scaladsl.server.directives.CodingDirectives.DefaultEncodeResponseEncoders
|
||||
.map(c ⇒ Coder.values().find(_._underlyingScalaCoder() == c).get)
|
||||
|
||||
private[http] val _DefaultCodersToDecodeRequest =
|
||||
scaladsl.server.directives.CodingDirectives.DefaultCoders
|
||||
.map(c ⇒ Coder.values().find(_._underlyingScalaCoder() == c).get)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives
|
||||
|
||||
import akka.http.impl.server.RouteStructure
|
||||
import akka.http.javadsl.model.headers.HttpCookie
|
||||
import akka.http.javadsl.server.Route
|
||||
|
||||
import scala.annotation.varargs
|
||||
|
||||
abstract class CookieDirectives extends CodingDirectives {
|
||||
/**
|
||||
* Adds a Set-Cookie header with the given cookies to all responses of its inner route.
|
||||
*/
|
||||
@varargs def setCookie(cookie: HttpCookie, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.SetCookie(cookie)(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
|
@ -9,11 +9,11 @@ import akka.http.impl.server.RouteStructure
|
|||
|
||||
import scala.annotation.varargs
|
||||
|
||||
abstract class ExecutionDirectives extends CodingDirectives {
|
||||
abstract class ExecutionDirectives extends CookieDirectives {
|
||||
/**
|
||||
* Handles exceptions in the inner routes using the specified handler.
|
||||
*/
|
||||
@varargs
|
||||
def handleExceptions(handler: ExceptionHandler, innerRoutes: Route*): Route =
|
||||
RouteStructure.HandleExceptions(handler, innerRoutes.toVector)
|
||||
def handleExceptions(handler: ExceptionHandler, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.HandleExceptions(handler)(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
package directives
|
||||
|
||||
import java.lang.{ Iterable ⇒ JIterable, Boolean ⇒ JBoolean }
|
||||
|
||||
import scala.annotation.varargs
|
||||
import scala.collection.JavaConverters._
|
||||
|
||||
import akka.http.impl.server.RouteStructure.{ GenericHostFilter, HostNameFilter }
|
||||
|
||||
abstract class HostDirectives extends FileAndResourceDirectives {
|
||||
/**
|
||||
* Rejects all requests with a host name different from the given one.
|
||||
*/
|
||||
@varargs
|
||||
def host(hostName: String, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
HostNameFilter(hostName :: Nil)(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* Rejects all requests with a host name different from the given ones.
|
||||
*/
|
||||
@varargs
|
||||
def host(hostNames: JIterable[String], innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
HostNameFilter(hostNames.asScala.toList)(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
/**
|
||||
* Rejects all requests for whose host name the given predicate function returns false.
|
||||
*/
|
||||
@varargs
|
||||
def host(predicate: akka.japi.function.Function[String, JBoolean], innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
new GenericHostFilter(innerRoute, moreInnerRoutes.toList) {
|
||||
def filter(hostName: String): Boolean = predicate.apply(hostName)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,36 +10,36 @@ import akka.http.impl.server.RouteStructure
|
|||
|
||||
import scala.annotation.varargs
|
||||
|
||||
abstract class MethodDirectives extends FileAndResourceDirectives {
|
||||
abstract class MethodDirectives extends HostDirectives {
|
||||
/** Handles the inner routes if the incoming request is a GET request, rejects the request otherwise */
|
||||
@varargs
|
||||
def get(innerRoutes: Route*): Route = method(HttpMethods.GET, innerRoutes: _*)
|
||||
def get(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.GET, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a POST request, rejects the request otherwise */
|
||||
@varargs
|
||||
def post(innerRoutes: Route*): Route = method(HttpMethods.POST, innerRoutes: _*)
|
||||
def post(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.POST, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a PUT request, rejects the request otherwise */
|
||||
@varargs
|
||||
def put(innerRoutes: Route*): Route = method(HttpMethods.PUT, innerRoutes: _*)
|
||||
def put(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.PUT, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a DELETE request, rejects the request otherwise */
|
||||
@varargs
|
||||
def delete(innerRoutes: Route*): Route = method(HttpMethods.DELETE, innerRoutes: _*)
|
||||
def delete(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.DELETE, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a HEAD request, rejects the request otherwise */
|
||||
@varargs
|
||||
def head(innerRoutes: Route*): Route = method(HttpMethods.HEAD, innerRoutes: _*)
|
||||
def head(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.HEAD, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a OPTIONS request, rejects the request otherwise */
|
||||
@varargs
|
||||
def options(innerRoutes: Route*): Route = method(HttpMethods.OPTIONS, innerRoutes: _*)
|
||||
def options(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.OPTIONS, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a PATCH request, rejects the request otherwise */
|
||||
@varargs
|
||||
def patch(innerRoutes: Route*): Route = method(HttpMethods.PATCH, innerRoutes: _*)
|
||||
def patch(innerRoute: Route, moreInnerRoutes: Route*): Route = method(HttpMethods.PATCH, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/** Handles the inner routes if the incoming request is a request with the given method, rejects the request otherwise */
|
||||
@varargs
|
||||
def method(method: HttpMethod, innerRoutes: Route*): Route = RouteStructure.MethodFilter(method, innerRoutes.toVector)
|
||||
def method(method: HttpMethod, innerRoute: Route, moreInnerRoutes: Route*): Route = RouteStructure.MethodFilter(method)(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
package directives
|
||||
|
||||
import java.lang.{ Boolean ⇒ JBoolean }
|
||||
|
||||
import akka.http.impl.server.RouteStructure.{ DynamicDirectiveRoute2, Validated, DynamicDirectiveRoute1 }
|
||||
|
||||
import scala.annotation.varargs
|
||||
import akka.japi.function.{ Function2, Function }
|
||||
|
||||
abstract class MiscDirectives extends MethodDirectives {
|
||||
/**
|
||||
* Returns a Route which checks the given condition on the request context before running its inner Route.
|
||||
* If the condition fails the route is rejected with a [[spray.routing.ValidationRejection]].
|
||||
*/
|
||||
@varargs
|
||||
def validate(check: Function[RequestContext, JBoolean], errorMsg: String, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
validate(RequestVals.requestContext, check, errorMsg, innerRoute, moreInnerRoutes: _*)
|
||||
|
||||
/**
|
||||
* Returns a Route which checks the given condition before running its inner Route. If the condition fails the
|
||||
* route is rejected with a [[spray.routing.ValidationRejection]].
|
||||
*/
|
||||
@varargs
|
||||
def validate[T](value: RequestVal[T], check: Function[T, JBoolean], errorMsg: String, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
new DynamicDirectiveRoute1[T](value)(innerRoute, moreInnerRoutes.toList) {
|
||||
def createDirective(t1: T): Directive = Directives.custom(Validated(check.apply(t1), errorMsg))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Route which checks the given condition before running its inner Route. If the condition fails the
|
||||
* route is rejected with a [[spray.routing.ValidationRejection]].
|
||||
*/
|
||||
@varargs
|
||||
def validate[T1, T2](value1: RequestVal[T1],
|
||||
value2: RequestVal[T2],
|
||||
check: Function2[T1, T2, JBoolean],
|
||||
errorMsg: String,
|
||||
innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
new DynamicDirectiveRoute2[T1, T2](value1, value2)(innerRoute, moreInnerRoutes.toList) {
|
||||
def createDirective(t1: T1, t2: T2): Directive = Directives.custom(Validated(check.apply(t1, t2), errorMsg))
|
||||
}
|
||||
}
|
||||
|
|
@ -6,12 +6,14 @@ package akka.http.javadsl.server
|
|||
package directives
|
||||
|
||||
import akka.http.impl.server.RouteStructure
|
||||
import akka.http.impl.server.RouteStructure.{ RedirectToNoTrailingSlashIfPresent, RedirectToTrailingSlashIfMissing }
|
||||
import akka.http.javadsl.model.StatusCode
|
||||
import akka.http.javadsl.server.values.{ PathMatchers, PathMatcher }
|
||||
|
||||
import scala.annotation.varargs
|
||||
import scala.collection.immutable
|
||||
|
||||
abstract class PathDirectives extends MethodDirectives {
|
||||
abstract class PathDirectives extends MiscDirectives {
|
||||
/**
|
||||
* Tries to consumes the complete unmatched path given a number of PathMatchers. Between each
|
||||
* of the matchers a `/` will be matched automatically.
|
||||
|
|
@ -20,20 +22,48 @@ abstract class PathDirectives extends MethodDirectives {
|
|||
*/
|
||||
@varargs
|
||||
def path(matchers: AnyRef*): Directive =
|
||||
forMatchers(joinWithSlash(convertMatchers(matchers)) :+ PathMatchers.END)
|
||||
RawPathPrefixForMatchers(joinWithSlash(convertMatchers(matchers)) :+ PathMatchers.END)
|
||||
|
||||
@varargs
|
||||
def pathPrefix(matchers: AnyRef*): Directive =
|
||||
forMatchers(joinWithSlash(convertMatchers(matchers)))
|
||||
RawPathPrefixForMatchers(joinWithSlash(convertMatchers(matchers)))
|
||||
|
||||
def pathSingleSlash: Directive = forMatchers(List(PathMatchers.SLASH, PathMatchers.END))
|
||||
@varargs
|
||||
def pathPrefixTest(matchers: AnyRef*): Directive =
|
||||
RawPathPrefixTestForMatchers(joinWithSlash(convertMatchers(matchers)))
|
||||
|
||||
@varargs
|
||||
def rawPathPrefix(matchers: AnyRef*): Directive =
|
||||
forMatchers(convertMatchers(matchers))
|
||||
RawPathPrefixForMatchers(convertMatchers(matchers))
|
||||
|
||||
private def forMatchers(matchers: immutable.Seq[PathMatcher[_]]): Directive =
|
||||
Directives.custom(RouteStructure.RawPathPrefix(matchers, _))
|
||||
@varargs
|
||||
def rawPathPrefixTest(matchers: AnyRef*): Directive =
|
||||
RawPathPrefixTestForMatchers(convertMatchers(matchers))
|
||||
|
||||
@varargs
|
||||
def pathSuffix(matchers: AnyRef*): Directive =
|
||||
Directives.custom(RouteStructure.PathSuffix(convertMatchers(matchers)))
|
||||
|
||||
@varargs
|
||||
def pathSuffixTest(matchers: AnyRef*): Directive =
|
||||
Directives.custom(RouteStructure.PathSuffixTest(convertMatchers(matchers)))
|
||||
|
||||
def pathEnd: Directive = RawPathPrefixForMatchers(PathMatchers.END :: Nil)
|
||||
def pathSingleSlash: Directive = RawPathPrefixForMatchers(List(PathMatchers.SLASH, PathMatchers.END))
|
||||
def pathEndOrSingleSlash: Directive = RawPathPrefixForMatchers(List(PathMatchers.SLASH.optional, PathMatchers.END))
|
||||
|
||||
@varargs
|
||||
def redirectToTrailingSlashIfMissing(redirectionStatusCode: StatusCode, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RedirectToTrailingSlashIfMissing(redirectionStatusCode)(innerRoute, moreInnerRoutes.toList)
|
||||
@varargs
|
||||
def redirectToNoTrailingSlashIfPresent(redirectionStatusCode: StatusCode, innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RedirectToNoTrailingSlashIfPresent(redirectionStatusCode)(innerRoute, moreInnerRoutes.toList)
|
||||
|
||||
private def RawPathPrefixForMatchers(matchers: immutable.Seq[PathMatcher[_]]): Directive =
|
||||
Directives.custom(RouteStructure.RawPathPrefix(matchers))
|
||||
|
||||
private def RawPathPrefixTestForMatchers(matchers: immutable.Seq[PathMatcher[_]]): Directive =
|
||||
Directives.custom(RouteStructure.RawPathPrefixTest(matchers))
|
||||
|
||||
private def joinWithSlash(matchers: immutable.Seq[PathMatcher[_]]): immutable.Seq[PathMatcher[_]] = {
|
||||
def join(result: immutable.Seq[PathMatcher[_]], next: PathMatcher[_]): immutable.Seq[PathMatcher[_]] =
|
||||
|
|
@ -46,6 +76,7 @@ abstract class PathDirectives extends MethodDirectives {
|
|||
def parse(matcher: AnyRef): PathMatcher[_] = matcher match {
|
||||
case p: PathMatcher[_] ⇒ p
|
||||
case name: String ⇒ PathMatchers.segment(name)
|
||||
case x ⇒ throw new IllegalArgumentException(s"Matcher of class ${x.getClass} is unsupported for PathDirectives")
|
||||
}
|
||||
|
||||
matchers.map(parse).toVector
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
package directives
|
||||
|
||||
import akka.http.impl.server.RouteStructure.RangeSupport
|
||||
|
||||
import scala.annotation.varargs
|
||||
|
||||
abstract class RangeDirectives extends PathDirectives {
|
||||
/**
|
||||
* Answers GET requests with an `Accept-Ranges: bytes` header and converts HttpResponses coming back from its inner
|
||||
* route into partial responses if the initial request contained a valid `Range` request header. The requested
|
||||
* byte-ranges may be coalesced.
|
||||
* This directive is transparent to non-GET requests
|
||||
* Rejects requests with unsatisfiable ranges `UnsatisfiableRangeRejection`.
|
||||
* Rejects requests with too many expected ranges.
|
||||
*
|
||||
* Note: if you want to combine this directive with `conditional(...)` you need to put
|
||||
* it on the *inside* of the `conditional(...)` directive, i.e. `conditional(...)` must be
|
||||
* on a higher level in your route structure in order to function correctly.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7233
|
||||
*/
|
||||
@varargs def withRangeSupport(innerRoute: Route, moreInnerRoutes: Route*): Route = RangeSupport()(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
package directives
|
||||
|
||||
import akka.http.impl.server.RouteStructure.Redirect
|
||||
import akka.http.javadsl.model.{ StatusCode, Uri }
|
||||
|
||||
abstract class RouteDirectives extends RangeDirectives {
|
||||
/**
|
||||
* Completes the request with redirection response of the given type to the given URI.
|
||||
*
|
||||
* The ``redirectionType`` must be a StatusCode for which ``isRedirection`` returns true.
|
||||
*/
|
||||
def redirect(uri: Uri, redirectionType: StatusCode): Route = Redirect(uri, redirectionType)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.directives
|
||||
|
||||
import akka.http.impl.server.RouteStructure.SchemeFilter
|
||||
import akka.http.javadsl.server.Route
|
||||
|
||||
import scala.annotation.varargs
|
||||
|
||||
abstract class SchemeDirectives extends RouteDirectives {
|
||||
/**
|
||||
* Rejects all requests whose Uri scheme does not match the given one.
|
||||
*/
|
||||
@varargs
|
||||
def scheme(scheme: String, innerRoute: Route, moreInnerRoutes: Route*): Route = SchemeFilter(scheme)(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
package directives
|
||||
|
||||
import akka.http.impl.server.RouteStructure
|
||||
import akka.http.javadsl.model.ws.Message
|
||||
import akka.stream.javadsl.Flow
|
||||
|
||||
abstract class WebsocketDirectives extends SchemeDirectives {
|
||||
/**
|
||||
* Handles websocket requests with the given handler and rejects other requests with a
|
||||
* [[ExpectedWebsocketRequestRejection]].
|
||||
*/
|
||||
def handleWebsocketMessages(handler: Flow[Message, Message, Any]): Route =
|
||||
RouteStructure.HandleWebsocketMessages(handler)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values
|
||||
|
||||
import akka.http.impl.server.{ RouteStructure, CookieImpl }
|
||||
import akka.http.javadsl.server.{ Directive, RequestVal, Route }
|
||||
import akka.japi.Option
|
||||
|
||||
import scala.annotation.varargs
|
||||
import scala.collection.immutable
|
||||
|
||||
abstract class Cookie {
|
||||
def name(): String
|
||||
def domain(): Option[String]
|
||||
def path(): Option[String]
|
||||
|
||||
def withDomain(domain: String): Cookie
|
||||
def withPath(path: String): Cookie
|
||||
|
||||
def value(): RequestVal[String]
|
||||
def optionalValue(): RequestVal[Option[String]]
|
||||
|
||||
def set(value: String): Directive
|
||||
|
||||
@varargs
|
||||
def delete(innerRoute: Route, moreInnerRoutes: Route*): Route =
|
||||
RouteStructure.DeleteCookie(name(), domain(), path())(innerRoute, moreInnerRoutes.toList)
|
||||
}
|
||||
object Cookies {
|
||||
def create(name: String): Cookie = new CookieImpl(name)
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server
|
||||
package values
|
||||
|
||||
import java.{ lang ⇒ jl }
|
||||
import akka.japi.{ Option ⇒ JOption }
|
||||
|
||||
import akka.http.impl.server.FormFieldImpl
|
||||
import akka.http.scaladsl.unmarshalling._
|
||||
|
||||
trait FormField[T] extends RequestVal[T] {
|
||||
def optional: RequestVal[JOption[T]]
|
||||
def withDefault(defaultValue: T): RequestVal[T]
|
||||
}
|
||||
|
||||
object FormFields {
|
||||
import akka.http.scaladsl.common.ToNameReceptacleEnhancements._
|
||||
|
||||
def stringValue(name: String): FormField[String] = FormFieldImpl(name)
|
||||
def intValue(name: String): FormField[jl.Integer] = FormFieldImpl(name.as[Int])
|
||||
def byteValue(name: String): FormField[jl.Byte] = FormFieldImpl(name.as[Byte])
|
||||
def shortValue(name: String): FormField[jl.Short] = FormFieldImpl(name.as[Short])
|
||||
def longValue(name: String): FormField[jl.Long] = FormFieldImpl(name.as[Long])
|
||||
def floatValue(name: String): FormField[jl.Float] = FormFieldImpl(name.as[Float])
|
||||
def doubleValue(name: String): FormField[jl.Double] = FormFieldImpl(name.as[Double])
|
||||
def booleanValue(name: String): FormField[jl.Boolean] = FormFieldImpl(name.as[Boolean])
|
||||
|
||||
def hexByteValue(name: String): FormField[jl.Byte] = FormFieldImpl(name.as(Unmarshaller.HexByte))
|
||||
def hexShortValue(name: String): FormField[jl.Short] = FormFieldImpl(name.as(Unmarshaller.HexShort))
|
||||
def hexIntValue(name: String): FormField[jl.Integer] = FormFieldImpl(name.as(Unmarshaller.HexInt))
|
||||
def hexLongValue(name: String): FormField[jl.Long] = FormFieldImpl(name.as(Unmarshaller.HexLong))
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package akka.http.javadsl.server.values
|
||||
|
||||
import akka.http.impl.server.HeaderImpl
|
||||
import akka.http.javadsl.model.HttpHeader
|
||||
import akka.http.javadsl.server.RequestVal
|
||||
import akka.http.scaladsl.model
|
||||
import akka.http.scaladsl.server.Directive1
|
||||
import akka.http.scaladsl.server.util.ClassMagnet
|
||||
|
||||
import scala.reflect.{ ClassTag, classTag }
|
||||
|
||||
trait Header[T <: HttpHeader] {
|
||||
def instance(): RequestVal[T]
|
||||
def optionalInstance(): RequestVal[Option[T]]
|
||||
|
||||
def value(): RequestVal[String]
|
||||
def optionalValue(): RequestVal[Option[String]]
|
||||
}
|
||||
object Headers {
|
||||
import akka.http.scaladsl.server.directives.BasicDirectives._
|
||||
import akka.http.scaladsl.server.directives.HeaderDirectives._
|
||||
|
||||
def byName(name: String): Header[HttpHeader] =
|
||||
HeaderImpl[HttpHeader](name, _ ⇒ optionalHeaderInstanceByName(name.toLowerCase()), classTag[HttpHeader])
|
||||
|
||||
def byClass[T <: HttpHeader](clazz: Class[T]): Header[T] =
|
||||
HeaderImpl[T](clazz.getSimpleName, ct ⇒ optionalHeaderValueByType(ClassMagnet()(ct)), ClassTag(clazz))
|
||||
|
||||
private def optionalHeaderInstanceByName(lowercaseName: String): Directive1[Option[model.HttpHeader]] =
|
||||
extract(_.request.headers.collectFirst {
|
||||
case h @ model.HttpHeader(`lowercaseName`, _) ⇒ h
|
||||
})
|
||||
}
|
||||
|
|
@ -54,5 +54,5 @@ abstract class HttpBasicAuthenticator[T](val realm: String) extends AbstractDire
|
|||
* INTERNAL API
|
||||
*/
|
||||
protected[http] final def createRoute(first: Route, others: Array[Route]): Route =
|
||||
RouteStructure.BasicAuthentication(this, (first +: others).toVector)
|
||||
RouteStructure.BasicAuthentication(this)(first, others.toList)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,30 @@
|
|||
|
||||
package akka.http.javadsl.server.values
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry
|
||||
import java.{ lang ⇒ jl }
|
||||
|
||||
import akka.http.impl.server.ParameterImpl
|
||||
import java.util.{ Map ⇒ JMap, Collection ⇒ JCollection }
|
||||
|
||||
import akka.http.scaladsl.server.directives.ParameterDirectives
|
||||
import akka.http.scaladsl.unmarshalling.Unmarshaller
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
import akka.japi.{ Option ⇒ JOption }
|
||||
|
||||
import akka.http.impl.server.{ StandaloneExtractionImpl, ParameterImpl }
|
||||
import akka.http.javadsl.server.RequestVal
|
||||
import akka.http.scaladsl.server.Directive1
|
||||
import akka.http.scaladsl.server.directives.ParameterDirectives.ParamMagnet
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
/**
|
||||
* A RequestVal representing a query parameter of type T.
|
||||
*/
|
||||
trait Parameter[T] extends RequestVal[T]
|
||||
trait Parameter[T] extends RequestVal[T] {
|
||||
def optional: RequestVal[JOption[T]]
|
||||
def withDefault(defaultValue: T): RequestVal[T]
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of predefined parameters.
|
||||
|
|
@ -29,17 +39,29 @@ object Parameters {
|
|||
/**
|
||||
* A string query parameter.
|
||||
*/
|
||||
def string(name: String): Parameter[String] =
|
||||
fromScalaParam(implicit ec ⇒ ParamMagnet(name))
|
||||
def stringValue(name: String): Parameter[String] = ParameterImpl(name)
|
||||
|
||||
/**
|
||||
* An integer query parameter.
|
||||
*/
|
||||
def integer(name: String): Parameter[jl.Integer] =
|
||||
fromScalaParam[jl.Integer](implicit ec ⇒
|
||||
ParamMagnet(name.as[Int]).asInstanceOf[ParamMagnet { type Out = Directive1[jl.Integer] }])
|
||||
def intValue(name: String): Parameter[jl.Integer] = ParameterImpl(name.as[Int])
|
||||
def byteValue(name: String): Parameter[jl.Byte] = ParameterImpl(name.as[Byte])
|
||||
def shortValue(name: String): Parameter[jl.Short] = ParameterImpl(name.as[Short])
|
||||
def longValue(name: String): Parameter[jl.Long] = ParameterImpl(name.as[Long])
|
||||
def floatValue(name: String): Parameter[jl.Float] = ParameterImpl(name.as[Float])
|
||||
def doubleValue(name: String): Parameter[jl.Double] = ParameterImpl(name.as[Double])
|
||||
def booleanValue(name: String): Parameter[jl.Boolean] = ParameterImpl(name.as[Boolean])
|
||||
|
||||
private def fromScalaParam[T: ClassTag](underlying: ExecutionContext ⇒ ParamMagnet { type Out = Directive1[T] }): Parameter[T] =
|
||||
new ParameterImpl[T](underlying)
|
||||
def hexByteValue(name: String): Parameter[jl.Byte] = ParameterImpl(name.as(Unmarshaller.HexByte))
|
||||
def hexShortValue(name: String): Parameter[jl.Short] = ParameterImpl(name.as(Unmarshaller.HexShort))
|
||||
def hexIntValue(name: String): Parameter[jl.Integer] = ParameterImpl(name.as(Unmarshaller.HexInt))
|
||||
def hexLongValue(name: String): Parameter[jl.Long] = ParameterImpl(name.as(Unmarshaller.HexLong))
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
def asMap: RequestVal[JMap[String, String]] = StandaloneExtractionImpl(ParameterDirectives.parameterMap.map(_.asJava))
|
||||
def asMultiMap: RequestVal[JMap[String, JCollection[String]]] =
|
||||
StandaloneExtractionImpl(ParameterDirectives.parameterMultiMap.map(_.mapValues(_.asJavaCollection).asJava))
|
||||
def asCollection: RequestVal[JCollection[JMap.Entry[String, String]]] =
|
||||
StandaloneExtractionImpl(ParameterDirectives.parameterSeq.map(_.map(e ⇒ new SimpleEntry(e._1, e._2): JMap.Entry[String, String]).asJavaCollection))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.{ lang ⇒ jl, util ⇒ ju }
|
|||
import akka.http.impl.server.PathMatcherImpl
|
||||
import akka.http.javadsl.server.RequestVal
|
||||
import akka.http.scaladsl.server.{ PathMatcher0, PathMatcher1, PathMatchers ⇒ ScalaPathMatchers }
|
||||
import akka.japi.Option
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.reflect.ClassTag
|
||||
|
|
@ -21,7 +22,9 @@ import scala.reflect.ClassTag
|
|||
* Using a PathMatcher with the [[Directives.path]] or [[Directives.pathPrefix]] directives
|
||||
* "consumes" a part of the path which is recorded in [[RequestContext.unmatchedPath]].
|
||||
*/
|
||||
trait PathMatcher[T] extends RequestVal[T]
|
||||
trait PathMatcher[T] extends RequestVal[T] {
|
||||
def optional: PathMatcher[Option[T]]
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of predefined path matchers.
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ sealed abstract class StrictForm {
|
|||
object StrictForm {
|
||||
sealed trait Field
|
||||
object Field {
|
||||
private[http] def fromString(value: String): Field = FromString(value)
|
||||
|
||||
private[StrictForm] final case class FromString(value: String) extends Field
|
||||
private[StrictForm] final case class FromPart(value: Multipart.FormData.BodyPart.Strict) extends Field
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ trait CodingDirectives {
|
|||
* identity, gzip or deflate then no encoding is used.
|
||||
*/
|
||||
def encodeResponse: Directive0 =
|
||||
encodeResponseWith(NoCoding, Gzip, Deflate)
|
||||
_encodeResponse(DefaultEncodeResponseEncoders)
|
||||
|
||||
/**
|
||||
* Encodes the response with the encoding that is requested by the client via the `Accept-
|
||||
|
|
@ -110,6 +110,8 @@ trait CodingDirectives {
|
|||
object CodingDirectives extends CodingDirectives {
|
||||
val DefaultCoders: immutable.Seq[Coder] = immutable.Seq(Gzip, Deflate, NoCoding)
|
||||
|
||||
private[http] val DefaultEncodeResponseEncoders = immutable.Seq(NoCoding, Gzip, Deflate)
|
||||
|
||||
def theseOrDefault[T >: Coder](these: Seq[T]): Seq[T] = if (these.isEmpty) DefaultCoders else these
|
||||
|
||||
import BasicDirectives._
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue