Не подтверждена Коммит bdc48510 создал по автору Mariia Skripchenko's avatar Mariia Skripchenko Зафиксировано автором GitHub
Просмотр файлов

KTOR-6356 Make DefaultHeaders plugin Kotlin native compatible (#3781)

владелец 66b3859d
[versions]
kotlin-version = "1.8.22"
kotlinx-html-version = "0.9.1"
kotlinx-datetime = "0.4.1"
coroutines-version = "1.7.2"
atomicfu-version = "0.20.2"
serialization-version = "1.5.1"
......@@ -86,6 +87,8 @@ kotlinx-serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-seria
kotlinx-html = { module = "org.jetbrains.kotlinx:kotlinx-html", version.ref = "kotlinx-html-version" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
netty-handler = { module = "io.netty:netty-handler", version.ref = "netty-version" }
netty-codec-http2 = { module = "io.netty:netty-codec-http2", version.ref = "netty-version" }
netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty-version" }
......
......@@ -3,3 +3,40 @@
*/
description = ""
kotlin {
sourceSets {
jvmAndNixMain {
dependencies {
api(libs.kotlinx.datetime)
}
}
}
createCInterop("utils", nixTargets()) {
defFile = File(projectDir, "nix/interop/utils.def")
}
}
val configuredVersion: String by rootProject.extra
val writeKtorVersionDefFile by tasks.registering {
File(projectDir, "nix/interop/utils.def").apply {
parentFile.mkdirs()
createNewFile()
}.writer().buffered().use { writer ->
writer.write(
"""
---
char* read_ktor_version() {
return "$configuredVersion";
}
""".trimIndent()
)
}
}
tasks.filter { it.name.startsWith("cinteropUtils") }.forEach {
it.dependsOn(writeKtorVersionDefFile)
}
/*
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package io.ktor.server.plugins.defaultheaders
import io.ktor.server.application.*
internal actual fun <T : Any> readKtorVersion(plugin: RouteScopedPluginBuilder<T>): String {
return plugin.javaClass.`package`.implementationVersion ?: "debug"
}
......@@ -11,7 +11,6 @@ import io.ktor.server.response.*
import io.ktor.util.date.*
import io.ktor.utils.io.*
import kotlinx.atomicfu.*
import java.util.*
/**
* A configuration for the [DefaultHeaders] plugin.
......@@ -32,7 +31,7 @@ public class DefaultHeadersConfig {
/**
* Provides a time source. Useful for testing.
*/
public var clock: Clock = Clock { System.currentTimeMillis() }
public var clock: Clock = Clock { kotlinx.datetime.Clock.System.now().toEpochMilliseconds() }
/**
* Utility interface for obtaining timestamp.
......@@ -64,38 +63,27 @@ public val DefaultHeaders: RouteScopedPlugin<DefaultHeadersConfig> = createRoute
"DefaultHeaders",
::DefaultHeadersConfig
) {
val ktorPackageVersion = if (pluginConfig.headers.getAll(HttpHeaders.Server) == null) {
pluginConfig::class.java.`package`.implementationVersion ?: "debug"
val ktorVersion = if (pluginConfig.headers.getAll(HttpHeaders.Server) == null) {
readKtorVersion(this)
} else {
"debug"
}
val headers = pluginConfig.headers.build()
val DATE_CACHE_TIMEOUT_MILLISECONDS = 1000
val GMT_TIMEZONE = TimeZone.getTimeZone("GMT")!!
var cachedDateTimeStamp = 0L
val calendar = object : ThreadLocal<Calendar>() {
override fun initialValue(): Calendar {
return Calendar.getInstance(GMT_TIMEZONE, Locale.ROOT)
}
}
fun now(time: Long): GMTDate {
return calendar.get().toDate(time)
}
fun calculateDateHeader(): String {
val captureCached = cachedDateTimeStamp
val currentTimeStamp = pluginConfig.clock.now()
if (captureCached + DATE_CACHE_TIMEOUT_MILLISECONDS <= currentTimeStamp) {
cachedDateTimeStamp = currentTimeStamp
pluginConfig.cachedDateText.value = now(currentTimeStamp).toHttpDate()
pluginConfig.cachedDateText.value = GMTDate(currentTimeStamp).toHttpDate()
}
return pluginConfig.cachedDateText.value
}
val serverHeader = "Ktor/$ktorPackageVersion"
val serverHeader = "Ktor/$ktorVersion"
onCallRespond { call, _ ->
headers.forEach { name, value ->
if (!call.response.headers.contains(name)) value.forEach { call.response.header(name, it) }
......@@ -109,3 +97,5 @@ public val DefaultHeaders: RouteScopedPlugin<DefaultHeadersConfig> = createRoute
}
}
}
internal expect fun <T : Any> readKtorVersion(plugin: RouteScopedPluginBuilder<T>): String
......@@ -40,9 +40,7 @@ class DefaultHeadersTest {
get { call.respond("OK") }
}
client.get("/").let { response ->
assertEquals("xserver/1.0", response.headers["Server"])
}
assertEquals("xserver/1.0", client.get("/").headers["Server"])
}
@Test
......@@ -61,9 +59,7 @@ class DefaultHeadersTest {
assertTrue(actual.startsWith("Ktor/"))
}
client.get("/2").let { response ->
assertNull(response.headers["Server"])
}
assertNull(client.get("/2").headers["Server"])
}
@Test
......
/*
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package io.ktor.server.plugins.defaultheaders
import io.ktor.server.application.*
import kotlinx.cinterop.*
import utils.*
@OptIn(ExperimentalForeignApi::class)
internal actual fun <T : Any> readKtorVersion(plugin: RouteScopedPluginBuilder<T>): String {
return read_ktor_version()?.toKString() ?: "debug"
}
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать