From acbcad6bee910d41c560dac4dbe7bce426282a0b Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 07:54:47 +0200 Subject: [PATCH 1/9] Enabling ssl & keystore --- build.gradle | 7 ++ config.json | 5 +- gradle.properties | 5 +- .../dmi/dbis/vrem/config/WebServerConfig.kt | 5 +- .../unibas/dmi/dbis/vrem/rest/APIEndpoint.kt | 67 ++++++++++++++++++- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index ccc075a..6439f1f 100644 --- a/build.gradle +++ b/build.gradle @@ -117,6 +117,7 @@ idea { repositories { mavenCentral() + maven { url "https://kotlin.bintray.com/kotlinx" } } dependencies { @@ -133,6 +134,12 @@ dependencies { // Javalin. implementation group: 'io.javalin', name: 'javalin', version: "$javalinVersion" + //jetty + implementation group: 'org.eclipse.jetty.http2', name: 'http2-server', version: "$jettyVersion" + implementation group: 'org.eclipse.jetty', name: 'jetty-alpn-conscrypt-server', version: "$jettyVersion" + implementation group: 'org.eclipse.jetty.alpn', name: 'alpn-api', version: "$alpnApiVersion" + implementation group: 'org.mortbay.jetty.alpn', name: 'alpn-boot', version: "$alpnBootVersion" + // Fuel. implementation group: 'com.github.kittinunf.fuel', name: 'fuel', version: "$fuelVersion" implementation group: 'com.github.kittinunf.fuel', name: 'fuel-kotlinx-serialization', version: "$fuelVersion" diff --git a/config.json b/config.json index 8eb4aaa..7a974da 100644 --- a/config.json +++ b/config.json @@ -6,7 +6,10 @@ }, "server": { "documentRoot": "data", - "port": 4545 + "port": 4545, + "enableSsl": false, + "keystorePath": "keystore.jks", + "keystorePassword": "password" }, "cineast": { "host": "127.0.0.1", diff --git a/gradle.properties b/gradle.properties index 4f13a4b..2bf593d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,10 @@ kotlinLoggingVersion=2.0.8 cliktVersion=2.8.0 kotlinxSerializationVersion=1.2.1 kmongoVersion=4.2.7 -javalinVersion=3.13.7 +javalinVersion=3.13.11 fuelVersion=2.3.1 okhttpVersion=4.9.0 moshiVersion=1.11.0 +jettyVersion = 9.4.25.v20191220 +alpnApiVersion = 1.1.3.v20160715 +alpnBootVersion = 8.1.12.v20180117 \ No newline at end of file diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt index 582f093..f68a05d 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt @@ -7,6 +7,9 @@ import kotlinx.serialization.Serializable * * @property documentRoot The document root path as a string. * @property port The port of the endpoint. + * @property enableSsl if ssl / https should be enabled + * @property keystorePassword password for the keystore + * @property keystorePath path for the keystore */ @Serializable -data class WebServerConfig(val documentRoot: String, val port: Short) +data class WebServerConfig(val documentRoot: String, val port: Int, val enableSsl: Boolean, val keystorePath: String, val keystorePassword: String) diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt index 2aa2260..94f42a2 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt @@ -20,9 +20,14 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.serializer import mu.KotlinLogging +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory +import org.eclipse.jetty.server.* +import org.eclipse.jetty.util.ssl.SslContextFactory import org.litote.kmongo.id.serialization.IdKotlinXSerializationModule import java.io.File import java.time.Duration +import java.util.function.Supplier private val logger = KotlinLogging.logger {} @@ -78,6 +83,8 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end val endpoint = Javalin.create { conf -> conf.defaultContentType = "application/json" conf.enableCorsForAllOrigins() + conf.server { setupHttpServer(config) } + conf.enforceSsl = config.server.enableSsl // Logger. /*conf.requestLogger { ctx, ms -> @@ -114,13 +121,13 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end endpoint.exception(Exception::class.java) { e, ctx -> logger.error(e) { "Exception occurred, sending 500 and exception name." } ctx.status(500) - .json(ErrorResponse("Error of type ${e.javaClass.simpleName} occurred. Check server log for additional information.")) + .json(ErrorResponse("Error of type ${e.javaClass.simpleName} occurred. Check server log for additional information.")) } endpoint.after { ctx -> ctx.header("Access-Control-Allow-Origin", "*") ctx.header("Access-Control-Allow-Headers", "*") } - endpoint.start(config.server.port.toInt()) + endpoint.start(config.server.port) println("Started the server.") println("Ctrl+C to stop the server.") @@ -128,4 +135,60 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end // TODO CLI to process commands (/quit and the like). } + private fun setupHttpServer(config: Config): Server { + + val httpConfig = HttpConfiguration().apply { + sendServerVersion = false + sendXPoweredBy = false + if (config.server.enableSsl) { + secureScheme = "https" + securePort = config.server.port + } + } + + /* + * Straight from https://www.eclipse.org/jetty/documentation/jetty-11/programming_guide.php encrypted http/2 + */ + if (config.server.enableSsl) { + val httpsConfig = HttpConfiguration(httpConfig).apply { + addCustomizer(SecureRequestCustomizer()) + } + + val fallback = HttpConnectionFactory(httpsConfig) + + val alpn = ALPNServerConnectionFactory().apply { + defaultProtocol = fallback.protocol + } + + val sslContextFactory = SslContextFactory.Server().apply { + keyStorePath = config.server.keystorePath + setKeyStorePassword(config.server.keystorePassword) + //cipherComparator = HTTP2Cipher.COMPARATOR + provider = "Conscrypt" + } + + val ssl = SslConnectionFactory(sslContextFactory, alpn.protocol) + + val http2 = HTTP2ServerConnectionFactory(httpsConfig) + + return Server().apply { + /*//HTTP Connector + addConnector(ServerConnector(server, HttpConnectionFactory(httpConfig), HTTP2ServerConnectionFactory(httpConfig)).apply { + port = config.server.port + })*/ + addConnector(ServerConnector(server, ssl, alpn, http2, fallback).apply { + port = config.server.port + }) + } + } else { + return Server().apply { + //HTTP Connector + addConnector(ServerConnector(server, HttpConnectionFactory(httpConfig), HTTP2ServerConnectionFactory(httpConfig)).apply { + port = config.server.port + }) + + } + } + } + } From 7477c37a7add97762c6377f39b5d11a0f731bde5 Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 10:16:02 +0200 Subject: [PATCH 2/9] excluding meta-inf from jar since it doesn't run otherwise because some dependencies are signed --- build.gradle | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6439f1f..1399efa 100644 --- a/build.gradle +++ b/build.gradle @@ -55,6 +55,8 @@ jar { from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + }{ + exclude 'META-INF', 'META-INF/**' } } @@ -132,8 +134,9 @@ dependencies { implementation group: 'org.litote.kmongo', name: 'kmongo-id-serialization', version: "$kmongoVersion" // Javalin. - implementation group: 'io.javalin', name: 'javalin', version: "$javalinVersion" - + implementation("io.javalin:javalin-bundle:$javalinVersion"){ + exclude group: 'ch.qos.logback', module: 'logback-classic' + } //jetty implementation group: 'org.eclipse.jetty.http2', name: 'http2-server', version: "$jettyVersion" implementation group: 'org.eclipse.jetty', name: 'jetty-alpn-conscrypt-server', version: "$jettyVersion" From 4d563f0725efd11d63a43b8106c587bf0402588d Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 10:24:08 +0200 Subject: [PATCH 3/9] re-including logback --- build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 1399efa..98aa47a 100644 --- a/build.gradle +++ b/build.gradle @@ -134,9 +134,7 @@ dependencies { implementation group: 'org.litote.kmongo', name: 'kmongo-id-serialization', version: "$kmongoVersion" // Javalin. - implementation("io.javalin:javalin-bundle:$javalinVersion"){ - exclude group: 'ch.qos.logback', module: 'logback-classic' - } + implementation("io.javalin:javalin-bundle:$javalinVersion") //jetty implementation group: 'org.eclipse.jetty.http2', name: 'http2-server', version: "$jettyVersion" implementation group: 'org.eclipse.jetty', name: 'jetty-alpn-conscrypt-server', version: "$jettyVersion" From 4dc888d326982b18600d85b69cea42c63d19ffa8 Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 10:57:21 +0200 Subject: [PATCH 4/9] works with distZip now --- build.gradle | 9 ++++--- config.json | 3 ++- gradle.properties | 10 +++---- .../dmi/dbis/vrem/config/WebServerConfig.kt | 5 ++-- .../unibas/dmi/dbis/vrem/rest/APIEndpoint.kt | 27 ++++++++++++------- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index 98aa47a..aa56c62 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ sourceSets { } // Jar properties. -jar { +tasks.named('jar') { manifest { attributes 'Version': archiveVersion.get() attributes 'Main-Class': mainClassName // Same as for the application plugin. @@ -55,9 +55,9 @@ jar { from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - }{ - exclude 'META-INF', 'META-INF/**' } + + exclude 'META-INF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' } // Generate Cineast OpenAPI bindings. @@ -134,7 +134,8 @@ dependencies { implementation group: 'org.litote.kmongo', name: 'kmongo-id-serialization', version: "$kmongoVersion" // Javalin. - implementation("io.javalin:javalin-bundle:$javalinVersion") + implementation group: 'io.javalin', name: 'javalin', version: "$javalinVersion" + //jetty implementation group: 'org.eclipse.jetty.http2', name: 'http2-server', version: "$jettyVersion" implementation group: 'org.eclipse.jetty', name: 'jetty-alpn-conscrypt-server', version: "$jettyVersion" diff --git a/config.json b/config.json index 7a974da..a69eaad 100644 --- a/config.json +++ b/config.json @@ -6,7 +6,8 @@ }, "server": { "documentRoot": "data", - "port": 4545, + "httpPort": 4544, + "httpsPort": 4545, "enableSsl": false, "keystorePath": "keystore.jks", "keystorePassword": "password" diff --git a/gradle.properties b/gradle.properties index 2bf593d..e71fdb4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,15 @@ javaCompatibility=11 -kotlinVersion=1.5.20 +kotlinVersion=1.5.30 openApiGenVersion=5.1.1 log4jslf4jVersion=2.14.1 kotlinLoggingVersion=2.0.8 cliktVersion=2.8.0 -kotlinxSerializationVersion=1.2.1 -kmongoVersion=4.2.7 +kotlinxSerializationVersion=1.2.2 +kmongoVersion=4.2.8 javalinVersion=3.13.11 fuelVersion=2.3.1 -okhttpVersion=4.9.0 -moshiVersion=1.11.0 +okhttpVersion=4.9.1 +moshiVersion=1.12.0 jettyVersion = 9.4.25.v20191220 alpnApiVersion = 1.1.3.v20160715 alpnBootVersion = 8.1.12.v20180117 \ No newline at end of file diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt index f68a05d..39d8124 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/config/WebServerConfig.kt @@ -6,10 +6,11 @@ import kotlinx.serialization.Serializable * Configuration of the REST endpoint. * * @property documentRoot The document root path as a string. - * @property port The port of the endpoint. + * @property httpPort The port of the endpoint. + * @property httpPort The port of the https endpoint. * @property enableSsl if ssl / https should be enabled * @property keystorePassword password for the keystore * @property keystorePath path for the keystore */ @Serializable -data class WebServerConfig(val documentRoot: String, val port: Int, val enableSsl: Boolean, val keystorePath: String, val keystorePassword: String) +data class WebServerConfig(val documentRoot: String, val httpPort: Int, val httpsPort: Int, val enableSsl: Boolean, val keystorePath: String, val keystorePassword: String) diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt index 94f42a2..25b78e4 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt @@ -27,7 +27,10 @@ import org.eclipse.jetty.util.ssl.SslContextFactory import org.litote.kmongo.id.serialization.IdKotlinXSerializationModule import java.io.File import java.time.Duration -import java.util.function.Supplier +import org.eclipse.jetty.util.thread.QueuedThreadPool + + + private val logger = KotlinLogging.logger {} @@ -127,7 +130,7 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end ctx.header("Access-Control-Allow-Origin", "*") ctx.header("Access-Control-Allow-Headers", "*") } - endpoint.start(config.server.port) + endpoint.start(config.server.httpPort) println("Started the server.") println("Ctrl+C to stop the server.") @@ -137,12 +140,15 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end private fun setupHttpServer(config: Config): Server { + val threadPool = QueuedThreadPool() + threadPool.name = "server" + val httpConfig = HttpConfiguration().apply { sendServerVersion = false sendXPoweredBy = false if (config.server.enableSsl) { secureScheme = "https" - securePort = config.server.port + securePort = config.server.httpsPort } } @@ -171,20 +177,21 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end val http2 = HTTP2ServerConnectionFactory(httpsConfig) - return Server().apply { - /*//HTTP Connector + return Server(threadPool).apply { + //HTTP Connector addConnector(ServerConnector(server, HttpConnectionFactory(httpConfig), HTTP2ServerConnectionFactory(httpConfig)).apply { - port = config.server.port - })*/ + port = config.server.httpPort + }) + // HTTPS Connector addConnector(ServerConnector(server, ssl, alpn, http2, fallback).apply { - port = config.server.port + port = config.server.httpsPort }) } } else { - return Server().apply { + return Server(threadPool).apply { //HTTP Connector addConnector(ServerConnector(server, HttpConnectionFactory(httpConfig), HTTP2ServerConnectionFactory(httpConfig)).apply { - port = config.server.port + port = config.server.httpPort }) } From 54ee33ced8c675b0c0e0bc7f9572c255b7a35ca5 Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 15:06:30 +0200 Subject: [PATCH 5/9] adding api endpoint /content/get/?path=path since wildcards with slashes don't work for security reasons apparently --- .gitignore | 7 +++++++ config.json | 2 +- .../ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt | 11 +++++++---- .../vrem/rest/handlers/RequestContentHandler.kt | 16 +++++++++++++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index e4e7f94..63386c3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,13 @@ data/ logs/ .idea/ out/ +bin/ + +## keystore +*.pem +*.jks +*.p12 + ### Kotlin ### # Compiled class file diff --git a/config.json b/config.json index a69eaad..5e865ba 100644 --- a/config.json +++ b/config.json @@ -8,7 +8,7 @@ "documentRoot": "data", "httpPort": 4544, "httpsPort": 4545, - "enableSsl": false, + "enableSsl": true, "keystorePath": "keystore.jks", "keystorePassword": "password" }, diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt index 25b78e4..9283543 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt @@ -30,8 +30,6 @@ import java.time.Duration import org.eclipse.jetty.util.thread.QueuedThreadPool - - private val logger = KotlinLogging.logger {} /** @@ -108,8 +106,13 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end post(exhibitionHandler::saveExhibition) } } - path("/content/get/:path") { - get(contentHandler::serveContent) + path("/content/") { + path("get/:path") { + get(contentHandler::serveContent) + } + path("get/"){ + get(contentHandler::serveContentBody) + } } path("/exhibits") { path("list") { diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt index a617d48..9874c0f 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt @@ -24,6 +24,12 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig const val URL_ID_SUFFIX = ".remote" } + fun serveContentBody(ctx:Context){ + val path = ctx.queryParam("path", "")!! + serve(ctx, path) + } + + /** * Serves the requested content. * @@ -33,6 +39,10 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig */ fun serveContent(ctx: Context) { val path = ctx.pathParam(PARAM_KEY_PATH) + serve(ctx,path) + } + + private fun serve(ctx: Context, path: String) { if (path.isBlank()) { logger.error { "The requested path was blank - did you forget to send the actual content path?" } @@ -41,7 +51,7 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig } if (path.endsWith(URL_ID_SUFFIX)) { - // ID is composed as exhibitionID/imageID.remote. + // ID is composed as exhibitionID/imageID.remote for cineast val id = path.substring(path.indexOf("/") + 1, path.indexOf(URL_ID_SUFFIX)) var resultBytes: ByteArray? = null @@ -67,8 +77,7 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig ctx.header("Access-Control-Allow-Headers", "*") ctx.result(resultBytes) - } else { - val absolute = docRoot.resolve(path) + } else { val absolute = docRoot.resolve(path) if (!Files.exists(absolute)) { logger.error { "Cannot serve $absolute as it does not exist." } @@ -87,4 +96,5 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig } } + } From 30d963b3d13d28ad04df0686fef99974a9ce1012 Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 15:11:28 +0200 Subject: [PATCH 6/9] readme patch for new deployment method, version bump --- README.md | 9 ++++----- build.gradle | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e85a83f..4663c79 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,9 @@ the [setup guide](https://github.com/VIRTUE-DBIS/virtual-exhibition-presenter/wi VREM can be built using [Gradle](http://gradle.org/). Building and running it is as simple as: ``` - ./gradlew clean deploy - cd build/libs - java -jar virtual-exhibition-manager-2.0.0-SNAPSHOT.jar - java -jar virtual-exhibition-manager-2.0.0-SNAPSHOT.jar + ./gradlew clean distZip + unzip build/distributions/virtual-exhibition-manager-$ + virtual-exhibition-manager-$/bin/virtual-exhibition-manager ``` Make sure you have the correct working directory set so VREM can properly import exhibitions and serve content. @@ -42,7 +41,7 @@ Before starting, you should adapt the configurations in your config.json file (s After doing so, you may serve stored exhibitions by running VREM with the following command: ``` - java -jar virtual-exhibition-manager-2.0.0-SNAPSHOT.jar server -c /path/to/your/config.json + virtual-exhibition-manager-$/bin/virtual-exhibition-manager server -c /path/to/your/config.json ``` ## Importing an exhibition diff --git a/build.gradle b/build.gradle index aa56c62..8528042 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ def javaCompatibility = 11 // Project settings. group 'ch.unibas.dmi.dbis' -version '2.0.0-SNAPSHOT' +version '2.1.0' // Main class. mainClassName = 'ch.unibas.dmi.dbis.vrem.VREMKt' From 4cbac46a513ed96957f788be91617c10a284c4ad Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 16:38:48 +0200 Subject: [PATCH 7/9] logging contenttype --- .../vrem/rest/handlers/RequestContentHandler.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt index 9874c0f..1796eb1 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt @@ -24,7 +24,7 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig const val URL_ID_SUFFIX = ".remote" } - fun serveContentBody(ctx:Context){ + fun serveContentBody(ctx: Context) { val path = ctx.queryParam("path", "")!! serve(ctx, path) } @@ -39,7 +39,7 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig */ fun serveContent(ctx: Context) { val path = ctx.pathParam(PARAM_KEY_PATH) - serve(ctx,path) + serve(ctx, path) } private fun serve(ctx: Context, path: String) { @@ -77,20 +77,21 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig ctx.header("Access-Control-Allow-Headers", "*") ctx.result(resultBytes) - } else { val absolute = docRoot.resolve(path) + } else { + val absolute = docRoot.resolve(path) if (!Files.exists(absolute)) { logger.error { "Cannot serve $absolute as it does not exist." } ctx.status(404) return } - - ctx.contentType(Files.probeContentType(absolute)) + val content = Files.probeContentType(absolute) + ctx.contentType(content) ctx.header("Transfer-Encoding", "identity") ctx.header("Access-Control-Allow-Origin", "*") ctx.header("Access-Control-Allow-Headers", "*") - logger.info { "Serving $absolute." } + logger.info { "Serving $absolute. as $content" } ctx.result(absolute.toFile().inputStream()) } From b882d77fc75b1a6f2049dfebe55b13d1220660c3 Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 16:45:08 +0200 Subject: [PATCH 8/9] also specifying content-type in header --- .../dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt index 1796eb1..9c89bab 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/handlers/RequestContentHandler.kt @@ -87,11 +87,12 @@ class RequestContentHandler(private val docRoot: Path, private val cineastConfig } val content = Files.probeContentType(absolute) ctx.contentType(content) + ctx.header("Content-Type", content); ctx.header("Transfer-Encoding", "identity") ctx.header("Access-Control-Allow-Origin", "*") ctx.header("Access-Control-Allow-Headers", "*") - logger.info { "Serving $absolute. as $content" } + logger.info { "Serving $absolute as $content" } ctx.result(absolute.toFile().inputStream()) } From 7117281a9cb2327458bbd4ecbb9aeccab5b1b044 Mon Sep 17 00:00:00 2001 From: Silvan Heller Date: Fri, 27 Aug 2021 16:50:28 +0200 Subject: [PATCH 9/9] adding static file serving at ./data --- src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt index 9283543..43eaa95 100644 --- a/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt +++ b/src/main/kotlin/ch/unibas/dmi/dbis/vrem/rest/APIEndpoint.kt @@ -12,6 +12,7 @@ import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.option import io.javalin.Javalin import io.javalin.apibuilder.ApiBuilder.* +import io.javalin.http.staticfiles.Location import io.javalin.plugin.json.FromJsonMapper import io.javalin.plugin.json.JavalinJson import io.javalin.plugin.json.ToJsonMapper @@ -87,6 +88,8 @@ class APIEndpoint : CliktCommand(name = "server", help = "Start the REST API end conf.server { setupHttpServer(config) } conf.enforceSsl = config.server.enableSsl + conf.addStaticFiles("./data", Location.EXTERNAL) + // Logger. /*conf.requestLogger { ctx, ms -> logger.info { "Request received: ${ctx.req.requestURI}" }