diff --git a/build.gradle b/build.gradle index 75ddc16..701f5b7 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ dependencies { compile "org.eclipse.jetty:jetty-server:9.4.27.v20200227" compile "org.eclipse.jetty:jetty-servlet:9.4.27.v20200227" - compile "com.github.DaikonWeb:daikon-core:1.1.0" + compile "com.github.DaikonWeb:daikon-core:1.2.0" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2" testImplementation "org.junit.jupiter:junit-jupiter-api:5.5.2" diff --git a/src/main/kotlin/daikon/BasicAuthentication.kt b/src/main/kotlin/daikon/BasicAuthentication.kt deleted file mode 100644 index a1e8842..0000000 --- a/src/main/kotlin/daikon/BasicAuthentication.kt +++ /dev/null @@ -1,49 +0,0 @@ -package daikon - -import daikon.core.HttpStatus.UNAUTHORIZED_401 -import daikon.core.Request -import daikon.core.RequestFlow.halt -import daikon.core.Response -import java.nio.charset.StandardCharsets.UTF_8 -import java.util.* - -class BasicAuthentication { - private val credentials = mutableListOf() - - fun addUser(username: String, password: String) { - credentials.add(Credential(username, password)) - } - - fun validate(req: Request, res: Response, realm: String) { - try { - val credential = credential(req.header("Authorization")) - - if (isForbidden(credential)) { - unauthorized(res, realm) - } - } catch (t: Throwable) { - unauthorized(res, realm) - } - - } - - private fun unauthorized(res: Response, realm: String) { - res.header("WWW-Authenticate", """Basic realm="$realm", charset="UTF-8"""") - halt(res, UNAUTHORIZED_401) - } - - private fun isForbidden(credential: Credential): Boolean { - return credentials.none { it == credential } - } - - private fun credential(header: String): Credential { - val credentials = String( - Base64.getDecoder().decode(header.replace("Basic ", "", true)), - UTF_8 - ).split(":") - - return Credential(credentials[0], credentials[1]) - } -} - -data class Credential(val username: String, val password: String) diff --git a/src/main/kotlin/daikon/DaikonServer.kt b/src/main/kotlin/daikon/DaikonServer.kt deleted file mode 100644 index c1e0974..0000000 --- a/src/main/kotlin/daikon/DaikonServer.kt +++ /dev/null @@ -1,141 +0,0 @@ -package daikon - -import daikon.core.* - -abstract class DaikonServer(port: Int = 4545, initializeActions: DaikonServer.() -> Unit = {}) : AutoCloseable { - private val routes = Routing() - private val beforeActions = Routing() - private val afterActions = Routing() - private val afterStartActions = mutableListOf<(Context) -> Unit>() - private val beforeStopActions = mutableListOf<(Context) -> Unit>() - private val exceptions = Exceptions() - private val basePath = mutableListOf("") - private val context = ServerContext(port) - private val basicAuth = BasicAuthentication() - - init { - initializeActions() - } - - protected abstract fun start(routingHandler: RoutingHandler): DaikonServer - protected abstract fun stop() - - fun start(): DaikonServer { - val routingHandler = RoutingHandler(beforeActions, routes, afterActions, context, exceptions) - start(routingHandler) - afterStartActions.forEach { it.invoke(context) } - return this - } - - override fun close() { - beforeStopActions.forEach { it.invoke(context) } - stop() - } - - fun exception(exception: Class, action: (Request, Response, Context, Throwable) -> Unit) - = exception(exception, ContextExceptionAction(action)) - - fun exception(exception: Class, action: (Request, Response, Throwable) -> Unit) - = exception(exception, DummyExceptionAction(action)) - - fun exception(exception: Class, action: ExceptionAction): DaikonServer { - exceptions.add(ExceptionRoute(exception, action)) - return this - } - - fun get(path: String, action: (Request, Response) -> Unit) = get(path, DummyRouteAction(action)) - - fun get(path: String, action: (Request, Response, Context) -> Unit) = get(path, ContextRouteAction(action)) - - fun get(path: String, action: RouteAction) = add(Method.GET, path, action) - - fun post(path: String, action: (Request, Response) -> Unit) = post(path, DummyRouteAction(action)) - - fun post(path: String, action: (Request, Response, Context) -> Unit) = post(path, ContextRouteAction(action)) - - fun post(path: String, action: RouteAction) = add(Method.POST, path, action) - - fun put(path: String, action: (Request, Response) -> Unit) = put(path, DummyRouteAction(action)) - - fun put(path: String, action: (Request, Response, Context) -> Unit) = put(path, ContextRouteAction(action)) - - fun put(path: String, action: RouteAction) = add(Method.PUT, path, action) - - fun delete(path: String, action: (Request, Response) -> Unit) = delete(path, DummyRouteAction(action)) - - fun delete(path: String, action: (Request, Response, Context) -> Unit) = delete(path, ContextRouteAction(action)) - - fun delete(path: String, action: RouteAction) = add(Method.DELETE, path, action) - - fun options(path: String, action: (Request, Response) -> Unit) = options(path, DummyRouteAction(action)) - - fun options(path: String, action: (Request, Response, Context) -> Unit) = options(path, ContextRouteAction(action)) - - fun options(path: String, action: RouteAction) = add(Method.OPTIONS, path, action) - - fun head(path: String, action: (Request, Response) -> Unit) = head(path, DummyRouteAction(action)) - - fun head(path: String, action: (Request, Response, Context) -> Unit) = head(path, ContextRouteAction(action)) - - fun head(path: String, action: RouteAction) = add(Method.HEAD, path, action) - - fun any(path: String, action: (Request, Response) -> Unit) = any(path, DummyRouteAction(action)) - - fun any(path: String, action: (Request, Response, Context) -> Unit) = any(path, ContextRouteAction(action)) - - fun any(path: String, action: RouteAction) = add(Method.ANY, path, action) - - fun before(path: String = "/*", action: (Request, Response) -> Unit): DaikonServer { - beforeActions.add(Route(Method.ANY, joinPaths(path), DummyRouteAction(action))) - return this - } - - fun before(path: String = "/*", action: (Request, Response, Context) -> Unit): DaikonServer { - beforeActions.add(Route(Method.ANY, joinPaths(path), ContextRouteAction(action))) - return this - } - - fun after(path: String = "/*", action: (Request, Response) -> Unit): DaikonServer { - afterActions.add(Route(Method.ANY, joinPaths(path), DummyRouteAction(action))) - return this - } - - fun after(path: String = "/*", action: (Request, Response, Context) -> Unit): DaikonServer { - afterActions.add(Route(Method.ANY, joinPaths(path), ContextRouteAction(action))) - return this - } - - fun path(path: String, nested: DaikonServer.() -> Unit): DaikonServer { - basePath.add(path) - nested.invoke(this) - basePath.removeAt(basePath.size - 1) - return this - } - - fun afterStart(function: (Context) -> Unit): DaikonServer { - afterStartActions.add(function) - return this - } - - fun beforeStop(function: (Context) -> Unit): DaikonServer { - beforeStopActions.add(function) - return this - } - - fun basicAuthUser(username: String, password: String): DaikonServer { - basicAuth.addUser(username, password) - return this - } - - fun basicAuth(path: String, realm: String = "default"): DaikonServer { - before(path) { req, res -> basicAuth.validate(req, res, realm) } - return this - } - - private fun add(method: Method, path: String, action: RouteAction): DaikonServer { - routes.add(Route(method, joinPaths(path), action)) - return this - } - - private fun joinPaths(path: String) = basePath.joinToString(separator = "") + path -} \ No newline at end of file diff --git a/src/main/kotlin/daikon/HttpServer.kt b/src/main/kotlin/daikon/HttpServer.kt index 081a592..6292604 100644 --- a/src/main/kotlin/daikon/HttpServer.kt +++ b/src/main/kotlin/daikon/HttpServer.kt @@ -1,5 +1,6 @@ package daikon +import daikon.core.DaikonServer import daikon.core.RoutingHandler import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.DefaultServlet @@ -11,7 +12,7 @@ import java.time.LocalDateTime.now import java.time.temporal.ChronoUnit.MILLIS -class HttpServer(private val port: Int = 4545, initializeActions: DaikonServer.() -> Unit = {}): DaikonServer(port, initializeActions) { +class HttpServer(private val port: Int = 4545, initializeActions: DaikonServer.() -> Unit = {}): DaikonServer(initializeActions) { init { disableJettyLog() } @@ -22,6 +23,7 @@ class HttpServer(private val port: Int = 4545, initializeActions: DaikonServer.( override fun start(routingHandler: RoutingHandler): HttpServer { val beginStarting = now() server = Server(port) + context.addAttribute("port", port) handler.addServlet(ServletHolder(RoutingServlet(routingHandler)), "/*") server.handler = handler server.start() diff --git a/src/main/kotlin/daikon/ServerContext.kt b/src/main/kotlin/daikon/ServerContext.kt deleted file mode 100644 index adb3f2f..0000000 --- a/src/main/kotlin/daikon/ServerContext.kt +++ /dev/null @@ -1,21 +0,0 @@ -package daikon - -import daikon.core.Context - -class ServerContext(private val port: Int) : Context { - - private val attributes = mutableMapOf() - - override fun addAttribute(key: String, value: Any) { - attributes[key] = value - } - - override fun getAttribute(key: String): T { - @Suppress("UNCHECKED_CAST") - return attributes[key] as T - } - - override fun port(): Int { - return port - } -} diff --git a/src/test/kotlin/daikon/PerformanceTest.kt b/src/test/kotlin/daikon/PerformanceTest.kt index 669db7f..6a40b22 100644 --- a/src/test/kotlin/daikon/PerformanceTest.kt +++ b/src/test/kotlin/daikon/PerformanceTest.kt @@ -1,5 +1,6 @@ package daikon +import daikon.core.DaikonServer import daikon.core.HttpStatus.OK_200 import kotlinx.coroutines.Deferred import kotlinx.coroutines.GlobalScope