diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4340c3f6e0..d2a527a9be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ on: push: - branches-ignore: [ master ] + branches-ignore: [ master, release/** ] permissions: contents: read diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8241c78e6b..c12b885203 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,6 @@ jobs: run: | export REMOTE="https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git" git remote set-url origin "$REMOTE" - git clone "$REMOTE" --branch gh-pages build/gh-pages ./gradlew build ./gradlew -x build buildSite ls -AlF site/build/site @@ -43,10 +42,3 @@ jobs: SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} run: ./gradlew --no-daemon -x test release - - - run: | - cp -rf site/build/site/* build/gh-pages/ - cd build/gh-pages - git add --all - git commit -m "Publishing to gh-pages" - git push origin gh-pages diff --git a/gradle.properties b/gradle.properties index 063a6c15d7..64083963f7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ org.gradle.warning.mode=all org.gradle.console=plain # Gradle -version=3.6.3 +version=3.6.4 group=com.hexagonkt description=The atoms of your platform diff --git a/http/http_server/api/http_server.api b/http/http_server/api/http_server.api index b2a2b69fbe..76be57a4bb 100644 --- a/http/http_server/api/http_server.api +++ b/http/http_server/api/http_server.api @@ -125,12 +125,10 @@ public final class com/hexagonkt/http/server/callbacks/UrlCallback : kotlin/jvm/ } public final class com/hexagonkt/http/server/handlers/CorsHandler : com/hexagonkt/http/handlers/HttpHandler { - public fun ()V public fun (Lcom/hexagonkt/http/server/callbacks/CorsCallback;)V public fun (Ljava/lang/String;Lcom/hexagonkt/http/server/callbacks/CorsCallback;)V - public synthetic fun (Ljava/lang/String;Lcom/hexagonkt/http/server/callbacks/CorsCallback;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun (Ljava/lang/String;Lkotlin/text/Regex;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ZLcom/hexagonkt/http/model/HttpStatus;J)V - public synthetic fun (Ljava/lang/String;Lkotlin/text/Regex;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ZLcom/hexagonkt/http/model/HttpStatus;JILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ZLcom/hexagonkt/http/model/HttpStatus;J)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ZLcom/hexagonkt/http/model/HttpStatus;JILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun addPrefix (Ljava/lang/String;)Lcom/hexagonkt/http/handlers/HttpHandler; public fun byMethod ()Ljava/util/Map; public fun filter (Lcom/hexagonkt/http/model/HttpMethod;)Lcom/hexagonkt/http/handlers/HttpHandler; diff --git a/http/http_server/src/main/kotlin/com/hexagonkt/http/server/handlers/CorsHandler.kt b/http/http_server/src/main/kotlin/com/hexagonkt/http/server/handlers/CorsHandler.kt index 508a228d34..d7e79a5db7 100644 --- a/http/http_server/src/main/kotlin/com/hexagonkt/http/server/handlers/CorsHandler.kt +++ b/http/http_server/src/main/kotlin/com/hexagonkt/http/server/handlers/CorsHandler.kt @@ -9,15 +9,14 @@ import com.hexagonkt.http.model.HttpStatus import com.hexagonkt.http.model.NO_CONTENT_204 import com.hexagonkt.http.server.callbacks.CorsCallback -// TODO Write tests -class CorsHandler(pattern: String = "*", cors: CorsCallback = CorsCallback()) : +class CorsHandler(pattern: String, cors: CorsCallback) : HttpHandler by FilterHandler(HttpPredicate(pattern = pattern), cors) { constructor(cors: CorsCallback) : this("*", cors) constructor( pattern: String = "*", - allowedOrigin: Regex, + allowedOrigin: String = "*", allowedMethods: Set = ALL, allowedHeaders: Set = emptySet(), exposedHeaders: Set = emptySet(), diff --git a/http/http_server_helidon/src/main/kotlin/com/hexagonkt/http/server/helidon/HelidonServerAdapter.kt b/http/http_server_helidon/src/main/kotlin/com/hexagonkt/http/server/helidon/HelidonServerAdapter.kt index 7454c4126f..a88f145609 100644 --- a/http/http_server_helidon/src/main/kotlin/com/hexagonkt/http/server/helidon/HelidonServerAdapter.kt +++ b/http/http_server_helidon/src/main/kotlin/com/hexagonkt/http/server/helidon/HelidonServerAdapter.kt @@ -137,7 +137,18 @@ class HelidonServerAdapter( setOf(ZIP) override fun options(): Map = - fieldsMapOf() + fieldsMapOf( + HelidonServerAdapter::backlog to backlog, + HelidonServerAdapter::writeQueueLength to writeQueueLength, + HelidonServerAdapter::readTimeout to readTimeout, + HelidonServerAdapter::connectTimeout to connectTimeout, + HelidonServerAdapter::tcpNoDelay to tcpNoDelay, + HelidonServerAdapter::receiveLog to receiveLog, + HelidonServerAdapter::sendLog to sendLog, + HelidonServerAdapter::validatePath to validatePath, + HelidonServerAdapter::validateRequestHeaders to validateRequestHeaders, + HelidonServerAdapter::validateResponseHeaders to validateResponseHeaders, + ) private fun setResponse( secureRequest: Boolean, diff --git a/http/http_test/src/main/kotlin/com/hexagonkt/http/test/examples/CorsTest.kt b/http/http_test/src/main/kotlin/com/hexagonkt/http/test/examples/CorsTest.kt index de3e2eaf04..90231e5a92 100644 --- a/http/http_test/src/main/kotlin/com/hexagonkt/http/test/examples/CorsTest.kt +++ b/http/http_test/src/main/kotlin/com/hexagonkt/http/test/examples/CorsTest.kt @@ -8,11 +8,11 @@ import com.hexagonkt.http.model.HttpMethod.POST import com.hexagonkt.http.model.NO_CONTENT_204 import com.hexagonkt.http.model.OK_200 import com.hexagonkt.http.server.* -import com.hexagonkt.http.server.callbacks.CorsCallback import com.hexagonkt.http.handlers.HandlerBuilder import com.hexagonkt.http.handlers.PathHandler import com.hexagonkt.http.handlers.HttpHandler import com.hexagonkt.http.handlers.path +import com.hexagonkt.http.server.callbacks.CorsCallback import com.hexagonkt.http.server.handlers.CorsHandler import com.hexagonkt.http.test.BaseTest import org.junit.jupiter.api.Test @@ -28,19 +28,19 @@ abstract class CorsTest( // cors val path: PathHandler = path { - corsPath("/default", CorsCallback()) - corsPath("/example/org", CorsCallback("example.org")) - corsPath("/no/credentials", CorsCallback(supportCredentials = false)) - corsPath("/only/post", CorsCallback(allowedMethods = setOf(POST))) - corsPath("/cache", CorsCallback(preFlightMaxAge = 10)) - corsPath("/exposed/headers", CorsCallback(exposedHeaders = setOf("head"))) - corsPath("/allowed/headers", CorsCallback(allowedHeaders = setOf("head"))) + corsPath("/default", CorsHandler(CorsCallback())) + corsPath("/example/org", CorsHandler(allowedOrigin = "example.org")) + corsPath("/no/credentials", CorsHandler(supportCredentials = false)) + corsPath("/only/post", CorsHandler(allowedMethods = setOf(POST))) + corsPath("/cache", CorsHandler(preFlightMaxAge = 10)) + corsPath("/exposed/headers", CorsHandler(exposedHeaders = setOf("head"))) + corsPath("/allowed/headers", CorsHandler(allowedHeaders = setOf("head"))) } - private fun HandlerBuilder.corsPath(path: String, cors: CorsCallback) { + private fun HandlerBuilder.corsPath(path: String, cors: CorsHandler) { path(path) { // CORS settings can change for different routes - use(CorsHandler(cors)) + use(cors) get("/path") { ok(method.toString()) } post("/path") { ok(method.toString()) } diff --git a/http/rest/build.gradle.kts b/http/rest/build.gradle.kts index d25487d4b4..85fbc63416 100644 --- a/http/rest/build.gradle.kts +++ b/http/rest/build.gradle.kts @@ -19,7 +19,11 @@ dependencies { "testImplementation"(project(":http:http_client_jetty")) "testImplementation"(project(":http:http_server_jetty")) + "testImplementation"(project(":serialization:serialization_jackson_csv")) "testImplementation"(project(":serialization:serialization_jackson_json")) + "testImplementation"(project(":serialization:serialization_jackson_toml")) + "testImplementation"(project(":serialization:serialization_jackson_xml")) + "testImplementation"(project(":serialization:serialization_jackson_yaml")) "testImplementation"("org.slf4j:log4j-over-slf4j:$slf4jVersion") "testImplementation"("org.slf4j:jcl-over-slf4j:$slf4jVersion") "testImplementation"("org.slf4j:slf4j-jdk14:$slf4jVersion") diff --git a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt index 56a4cae7c7..b9cc3f7783 100644 --- a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt +++ b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeRequestCallback.kt @@ -5,6 +5,7 @@ import com.hexagonkt.http.handlers.HttpContext import com.hexagonkt.serialization.SerializationManager import com.hexagonkt.serialization.serialize +// TODO Create SerializeRequestHandler like CorsHandler class SerializeRequestCallback : HttpCallback { init { diff --git a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt index 01b148d7ac..2ba73ff71b 100644 --- a/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt +++ b/http/rest/src/main/kotlin/com/hexagonkt/rest/SerializeResponseCallback.kt @@ -5,6 +5,7 @@ import com.hexagonkt.http.handlers.HttpContext import com.hexagonkt.serialization.SerializationManager import com.hexagonkt.serialization.serialize +// TODO Create SerializeResponseHandler like CorsHandler class SerializeResponseCallback: HttpCallback { init { diff --git a/http/rest/src/test/kotlin/com/hexagonkt/rest/RestTest.kt b/http/rest/src/test/kotlin/com/hexagonkt/rest/RestTest.kt index 8f4ce9ebd3..508e322c25 100644 --- a/http/rest/src/test/kotlin/com/hexagonkt/rest/RestTest.kt +++ b/http/rest/src/test/kotlin/com/hexagonkt/rest/RestTest.kt @@ -1,13 +1,20 @@ package com.hexagonkt.rest import com.hexagonkt.core.media.APPLICATION_JSON +import com.hexagonkt.core.media.APPLICATION_TOML +import com.hexagonkt.core.media.APPLICATION_XML import com.hexagonkt.core.media.APPLICATION_YAML +import com.hexagonkt.core.media.TEXT_CSV import com.hexagonkt.core.requireInt import com.hexagonkt.http.model.HttpResponse import com.hexagonkt.http.model.ContentType import com.hexagonkt.http.model.HttpRequest import com.hexagonkt.serialization.SerializationManager +import com.hexagonkt.serialization.jackson.csv.Csv import com.hexagonkt.serialization.jackson.json.Json +import com.hexagonkt.serialization.jackson.toml.Toml +import com.hexagonkt.serialization.jackson.xml.Xml +import com.hexagonkt.serialization.jackson.yaml.Yaml import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS @@ -30,10 +37,8 @@ internal class RestTest { ) } - private val json: ContentType = ContentType(APPLICATION_JSON) - @BeforeAll fun setUp() { - SerializationManager.formats = setOf(Json) + SerializationManager.formats = setOf(Json, Yaml, Xml, Toml, Csv) } @Test fun `Media type is calculated properly`() { @@ -48,47 +53,76 @@ internal class RestTest { } @Test fun `Body is parsed to list`() { - HttpRequest(body = """[ "a", "b", "c" ]""", contentType = json).apply { + HttpRequest(body = """[ "a", "b", "c" ]""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(listOf("a", "b", "c"), bodyList()) } - HttpResponse(body = """[ "a", "b", "c" ]""", contentType = json).apply { + HttpResponse(body = """[ "a", "b", "c" ]""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(listOf("a", "b", "c"), bodyList()) } } @Test fun `Body is parsed to map`() { - HttpRequest(body = """{ "a" : 0, "b" : 1, "c" : 2 }""", contentType = json).apply { + HttpRequest(body = """{"a":0,"b":1,"c":2}""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(mapOf("a" to 0, "b" to 1, "c" to 2), bodyMap()) } - HttpResponse(body = """{ "a" : 0, "b" : 1, "c" : 2 }""", contentType = json).apply { + HttpResponse(body = """{"a":0,"b":1,"c":2}""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(mapOf("a" to 0, "b" to 1, "c" to 2), bodyMap()) } } @Test fun `Body is parsed to objects`() { - HttpRequest(body = """{ "a" : 0, "b" : 1, "c" : 2 }""", contentType = json).apply { + HttpRequest(body = """{"a":0,"b":1,"c":2}""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(Record(mapOf("a" to 0, "b" to 1, "c" to 2)), bodyObject(::Record)) } - HttpResponse(body = """{ "a" : 0, "b" : 1, "c" : 2 }""", contentType = json).apply { + HttpResponse(body = """{"a":0,"b":1,"c":2}""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(Record(mapOf("a" to 0, "b" to 1, "c" to 2)), bodyObject(::Record)) } - HttpRequest(body = """[ { "a" : 0, "b" : 1, "c" : 2 } ]""", contentType = json).apply { + HttpRequest(body = """[{"a":0,"b":1,"c":2}]""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(listOf(Record(0, 1, 2)), bodyObjects(::Record)) } - HttpResponse(body = """[ { "a" : 0, "b" : 1, "c" : 2 } ]""", contentType = json).apply { + HttpResponse(body = """[{"a":0,"b":1,"c":2}]""", contentType = jsonContentType).apply { assertEquals(APPLICATION_JSON, mediaType()) assertEquals(listOf(Record(0, 1, 2)), bodyObjects(::Record)) } } - // TODO Test serialization with predefined content types @Test fun `Body is serialized`() { + val body1 = mapOf("a" to 0, "b" to 1, "c" to 2) + HttpResponse(body = body1, contentType = jsonContentType).apply { + assertEquals(APPLICATION_JSON, mediaType()) + val textBody = serializeBody().toString().replace(Regex("(\\s|\\n)*"), "") + assertEquals("""{"a":0,"b":1,"c":2}""", textBody) + } + val body2 = mapOf("a" to 3, "b" to 4, "c" to 5) + HttpResponse(body = body2, contentType = yamlContentType).apply { + assertEquals(APPLICATION_YAML, mediaType()) + val textBody = serializeBody().toString().replace(Regex("(\\s|\\n)*"), "") + assertEquals("""a:3b:4c:5""", textBody) + } + val body3 = mapOf("a" to 6, "b" to 7, "c" to 8) + HttpResponse(body = body3, contentType = xmlContentType).apply { + assertEquals(APPLICATION_XML, mediaType()) + val textBody = serializeBody().toString().replace(Regex("(\\s|\\n)*"), "") + assertEquals("""678""", textBody) + } + val body4 = mapOf("a" to 9, "b" to 10, "c" to 11) + HttpResponse(body = body4, contentType = tomlContentType).apply { + assertEquals(APPLICATION_TOML, mediaType()) + val textBody = serializeBody().toString().replace(Regex("(\\s|\\n)*"), "") + assertEquals("""a=9b=10c=11""", textBody) + } + val body5 = listOf(12, 13, 14) + HttpResponse(body = body5, contentType = csvContentType).apply { + assertEquals(TEXT_CSV, mediaType()) + val textBody = serializeBody().toString().replace(Regex("(\\s|\\n)*"), "") + assertEquals("""12,13,14""", textBody) + } } } diff --git a/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpClientTool.kt b/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpClientTool.kt index 4f655b9c82..5b78256185 100644 --- a/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpClientTool.kt +++ b/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpClientTool.kt @@ -27,6 +27,7 @@ data class HttpClientTool( val followRedirects: Boolean = false ) { companion object { + // TODO Use SerializeRequestHandler when created val serializeHandler: HttpHandler = BeforeHandler("*", SerializeRequestCallback()) } diff --git a/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpServerTool.kt b/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpServerTool.kt index 05697be85a..c241de5e0c 100644 --- a/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpServerTool.kt +++ b/http/rest_tools/src/main/kotlin/com/hexagonkt/rest/tools/HttpServerTool.kt @@ -23,6 +23,7 @@ data class HttpServerTool( private val server: HttpServer by lazy { HttpServer(adapter, settings) { + // TODO Use SerializeResponseHandler when created after("*", SerializeResponseCallback()) after(pattern = "*", status = NOT_FOUND_404) { send(response = this@HttpServerTool.path.process(request).response) diff --git a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpClientToolTest.kt b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpClientToolTest.kt index 8d3b9ad49f..0d76ee46a9 100644 --- a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpClientToolTest.kt +++ b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpClientToolTest.kt @@ -2,12 +2,12 @@ package com.hexagonkt.rest.tools import com.hexagonkt.core.media.TEXT_PLAIN import com.hexagonkt.http.client.jetty.JettyClientAdapter -import com.hexagonkt.http.model.ContentType import com.hexagonkt.http.model.HttpMethod.POST import com.hexagonkt.http.model.HttpMethod.PUT import com.hexagonkt.http.model.HttpResponsePort import com.hexagonkt.http.model.OK_200 import com.hexagonkt.http.server.jetty.JettyServletAdapter +import com.hexagonkt.rest.textContentType import com.hexagonkt.serialization.SerializationManager import com.hexagonkt.serialization.jackson.json.Json import org.junit.jupiter.api.AfterAll @@ -21,7 +21,7 @@ import kotlin.test.assertTrue @TestInstance(PER_CLASS) internal class HttpClientToolTest { private val server: HttpServerTool = HttpServerTool(JettyServletAdapter()) - private val text = ContentType(TEXT_PLAIN) + private val text = textContentType @BeforeAll fun `Set up mock services`() { SerializationManager.formats = setOf(Json) diff --git a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpServerToolTest.kt b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpServerToolTest.kt index 59d46485fa..705b046084 100644 --- a/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpServerToolTest.kt +++ b/http/rest_tools/src/test/kotlin/com/hexagonkt/rest/tools/HttpServerToolTest.kt @@ -1,13 +1,11 @@ package com.hexagonkt.rest.tools import com.hexagonkt.core.logging.info -import com.hexagonkt.core.media.APPLICATION_JSON import com.hexagonkt.core.media.TEXT_PLAIN import com.hexagonkt.core.require import com.hexagonkt.http.client.jetty.JettyClientAdapter import com.hexagonkt.http.handlers.FilterHandler import com.hexagonkt.http.handlers.PathHandler -import com.hexagonkt.http.model.ContentType import com.hexagonkt.http.model.OK_200 import com.hexagonkt.http.handlers.path import com.hexagonkt.http.model.HttpMethod.* @@ -16,6 +14,8 @@ import com.hexagonkt.http.model.HttpStatusType.SUCCESS import com.hexagonkt.http.server.HttpServerSettings import com.hexagonkt.http.server.jetty.JettyServletAdapter import com.hexagonkt.rest.bodyMap +import com.hexagonkt.rest.jsonContentType +import com.hexagonkt.rest.textContentType import com.hexagonkt.serialization.SerializationManager import com.hexagonkt.serialization.jackson.json.Json import org.junit.jupiter.api.AfterAll @@ -44,7 +44,7 @@ class HttpServerToolTest { get("/hello/{name}") { val name = pathParameters["name"] - ok("Hello, $name!", contentType = ContentType(TEXT_PLAIN)) + ok("Hello, $name!", contentType = textContentType) } } @@ -83,7 +83,7 @@ class HttpServerToolTest { @Test fun `Check all HTTP methods (absolute path)`() { dynamicServer.path = path { on("*") { - ok("$method $path ${request.headers}", contentType = ContentType(TEXT_PLAIN)) + ok("$method $path ${request.headers}", contentType = textContentType) } } @@ -131,7 +131,7 @@ class HttpServerToolTest { @Test fun `Check all HTTP methods`() { dynamicServer.path { before("*") { - ok("$method $path ${request.headers}", contentType = ContentType(TEXT_PLAIN)) + ok("$method $path ${request.headers}", contentType = textContentType) } } @@ -193,15 +193,13 @@ class HttpServerToolTest { val serverAdapter = JettyServletAdapter() val server = HttpServerTool(serverAdapter, settings).apply(HttpServerTool::start) val headers = mapOf("alfa" to "beta", "charlie" to listOf("delta", "echo")) - val text = ContentType(TEXT_PLAIN) - val json = ContentType(APPLICATION_JSON) val binding = server.binding.toString() val adapter = JettyClientAdapter() - val http = HttpClientTool(adapter, binding, json, httpHeaders = headers) + val http = HttpClientTool(adapter, binding, jsonContentType, httpHeaders = headers) server.path { before("*") { - ok("$method $path ${request.headers}", contentType = text) + ok("$method $path ${request.headers}", contentType = textContentType) } put("/data/{id}") { @@ -209,7 +207,7 @@ class HttpServerToolTest { val data = request.bodyMap() val content = mapOf(id to data) - ok(content, contentType = json) + ok(content, contentType = jsonContentType) } } @@ -280,11 +278,11 @@ class HttpServerToolTest { assertSuccess() assertStatus(OK_200) assertStatus(SUCCESS) - assertContentType(ContentType(TEXT_PLAIN)) + assertContentType(textContentType) assertContentType(TEXT_PLAIN) assertBodyContains(expectedBody) - assertEquals(ContentType(APPLICATION_JSON), request.contentType) + assertEquals(jsonContentType, request.contentType) assertEquals(OK_200, status) for ((k, v) in checkedHeaders.entries) { diff --git a/serverless/serverless_http_google/src/main/kotlin/com/hexagonkt/serverless/http/google/GoogleServerlessHttpAdapter.kt b/serverless/serverless_http_google/src/main/kotlin/com/hexagonkt/serverless/http/google/GoogleServerlessHttpAdapter.kt index 503173fa20..5da7ce3316 100644 --- a/serverless/serverless_http_google/src/main/kotlin/com/hexagonkt/serverless/http/google/GoogleServerlessHttpAdapter.kt +++ b/serverless/serverless_http_google/src/main/kotlin/com/hexagonkt/serverless/http/google/GoogleServerlessHttpAdapter.kt @@ -3,14 +3,69 @@ package com.hexagonkt.serverless.http.google import com.google.cloud.functions.HttpFunction import com.google.cloud.functions.HttpRequest import com.google.cloud.functions.HttpResponse +import com.hexagonkt.http.handlers.HttpContext import com.hexagonkt.http.handlers.HttpHandler +import com.hexagonkt.http.model.* +import com.hexagonkt.http.parseContentType +import java.net.URI -class GoogleServerlessHttpAdapter(val handler: HttpHandler): HttpFunction { +class GoogleServerlessHttpAdapter(private val handler: HttpHandler): HttpFunction { override fun service(request: HttpRequest, response: HttpResponse) { - // Transform request - response.writer.write("Hello World!") - // Call handler - // Transform response + val handlerRequest = createRequest(request) + val handlerContext = handler.process(handlerRequest) + writeResponse(response, handlerContext) + } + + private fun createRequest(request: HttpRequest): com.hexagonkt.http.model.HttpRequest { + val uri = URI(request.uri) + val qp = request.queryParameters?.map { (k, v) -> QueryParameter(k, v) } ?: emptyList() + val h = request.headers?.map { (k, v) -> Header(k, v) } ?: emptyList() + + request.parts.map { (k, v) -> + HttpPart( + name = k, + body = v.inputStream.readAllBytes(), + headers = Headers(), + contentType = v.contentType?.map { parseContentType(it) }?.orElse(null), + size = v.contentLength, + submittedFileName = v.fileName.orElse(null), + + /* + name: String, + body: Any, + headers: Headers = Headers(), + contentType: ContentType? = null, + size: Long = -1L, + submittedFileName: String? = null + */ + ) + } + + return HttpRequest( + method = HttpMethod.valueOf(request.method), + protocol = HttpProtocol.valueOf(uri.scheme.uppercase()), + host = uri.host, + port = uri.port, + path = request.path, + queryParameters = QueryParameters(qp), + headers = Headers(h), + body = request.inputStream.readAllBytes() ?: ByteArray(0), +// parts = pa, +// formParameters = fp, + contentType = request.contentType.map { parseContentType(it) }.orElse(null), +// accept = ac, + contentLength = request.contentLength, +// authorization = au, + ) + } + + private fun writeResponse(response: HttpResponse, context: HttpContext) { + val handlerResponse = context.response + + handlerResponse.contentType?.text?.let(response::setContentType) + handlerResponse.headers.forEach { (k, v) -> response.headers[k] = v.strings() } + response.setStatusCode(handlerResponse.status.code) + response.writer.write(handlerResponse.bodyString()) } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 255e75712a..ed26c64ce7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,9 +27,9 @@ dependencyResolutionManagement { version("detekt", "1.23.6") version("jmhGradle", "0.7.2") version("gradleWrapper", "8.10") - version("mkdocsMaterial", "9.5.31") + version("mkdocsMaterial", "9.5.32") version("mermaidDokka", "0.6.0") - version("maven", "3.9.8") + version("maven", "3.9.9") // Testing version("junit", "5.11.0")