Skip to content

Commit

Permalink
Release 2.3.12 (#4088)
Browse files Browse the repository at this point in the history
  • Loading branch information
marychatte committed Jun 20, 2024
1 parent b5d9213 commit c22735c
Show file tree
Hide file tree
Showing 18 changed files with 141 additions and 85 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ blank_issues_enabled: false
contact_links:
- name: Create
url: https://youtrack.jetbrains.com/newIssue?project=KTOR
about: Please report any new issue using youtrack
about: Please report any new issues to the JetBrains YouTrack
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# 2.3.12
> Published 20 June 2024
### Bugfixes
* NoSuchMethodError when using coroutines 1.9.0-RC ([KTOR-7054](https://youtrack.jetbrains.com/issue/KTOR-7054))
* Server: Content-Type header for static js, css and svg resources misses charset ([KTOR-6655](https://youtrack.jetbrains.com/issue/KTOR-6655))
* Embedded Linux device without iso-8859-1 and UTF-16 cannot use ktor-network ([KTOR-7016](https://youtrack.jetbrains.com/issue/KTOR-7016))

### Improvements
* Update netty to 4.1.111.Final ([KTOR-7094](https://youtrack.jetbrains.com/issue/KTOR-7094))
* Update netty due to CVE-2024-29025 ([KTOR-7014](https://youtrack.jetbrains.com/issue/KTOR-7014))
* Update dependency on swagger ([KTOR-7019](https://youtrack.jetbrains.com/issue/KTOR-7019))

# 2.3.11
> Published 8 May 2024
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ktor.ide.jvmAndCommonOnly=true
kotlin.code.style=official

# config
version=2.3.10
version=2.3.12

# gradle
org.gradle.daemon=true
Expand Down
22 changes: 11 additions & 11 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ serialization-version = "1.5.1"
validator-version = "0.8.0"
ktlint-version = "3.15.0"

netty-version = "4.1.106.Final"
netty-tcnative-version = "2.0.62.Final"
netty-version = "4.1.111.Final"
netty-tcnative-version = "2.0.65.Final"

jetty-version = "9.4.53.v20231009"
jetty-jakarta-version = "11.0.20"
jetty-version = "9.4.54.v20240208"
jetty-jakarta-version = "11.0.21"
jetty-alpn-api-version = "1.1.3.v20160715"
jetty-alpn-boot-version = "8.1.13.v20181017"
jetty-alpn-openjdk8 = "9.4.53.v20231009"
jetty-alpn-openjdk8 = "9.4.54.v20240208"

tomcat-version = "9.0.85"
tomcat-version = "9.0.89"
tomcat-jakarta-version = "10.1.18"

apache-version = "4.1.5"
Expand All @@ -30,10 +30,10 @@ gson-version = "2.10.1"
jackson-version = "2.16.1"

junit-version = "4.13.2"
slf4j-version = "2.0.11"
slf4j-version = "2.0.13"
logback-version = "1.3.14"

dropwizard-version = "4.2.25"
dropwizard-version = "4.2.26"
micrometer-version = "1.12.4"

jansi-version = "2.4.1"
Expand All @@ -44,8 +44,8 @@ mockk-version = "1.13.5"
java-jwt-version = "4.4.0"

jwks-rsa-version = "0.22.1"
mustache-version = "0.9.11"
freemarker-version = "2.3.32"
mustache-version = "0.9.13"
freemarker-version = "2.3.33"
pebble-version = "3.2.2"
velocity-version = "2.3"
velocity-tools-version = "3.1"
Expand All @@ -63,7 +63,7 @@ yamlkt-version = "0.13.0"

swagger-codegen-version = "3.0.41"
swagger-codegen-generators-version = "1.0.38"
swagger-parser-version = "2.1.19"
swagger-parser-version = "2.1.22"

[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin-version" }
Expand Down
25 changes: 24 additions & 1 deletion ktor-http/common/src/io/ktor/http/FileContentType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,34 @@ private val extensionsByContentType: Map<ContentType, List<String>> by lazy {
internal fun List<ContentType>.selectDefault(): ContentType {
val contentType = firstOrNull() ?: ContentType.Application.OctetStream
return when {
contentType.contentType == "text" && contentType.charset() == null -> contentType.withCharset(Charsets.UTF_8)
contentType.match(ContentType.Text.Any) -> contentType.withCharsetUTF8IfNeeded()
contentType.match(ContentType.Image.SVG) -> contentType.withCharsetUTF8IfNeeded()
contentType.matchApplicationTypeWithCharset() -> contentType.withCharsetUTF8IfNeeded()
else -> contentType
}
}

private fun ContentType.matchApplicationTypeWithCharset(): Boolean {
if (!match(ContentType.Application.Any)) return false

return when {
match(ContentType.Application.Atom) ||
match(ContentType.Application.JavaScript) ||
match(ContentType.Application.Rss) ||
match(ContentType.Application.Xml) ||
match(ContentType.Application.Xml_Dtd)
-> true

else -> false
}
}

private fun ContentType.withCharsetUTF8IfNeeded(): ContentType {
if (charset() != null) return this

return withCharset(Charsets.UTF_8)
}

internal fun <A, B> Sequence<Pair<A, B>>.groupByPairs() = groupBy { it.first }
.mapValues { e -> e.value.map { it.second } }

Expand Down
1 change: 1 addition & 0 deletions ktor-http/common/src/io/ktor/http/Mimes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ private val rawMimes: String
.jpgv,video/jpeg
.jpm,video/jpm
.jps,image/x-jps
.js,text/javascript
.js,application/javascript
.json,application/json
.jut,image/jutvision
Expand Down
6 changes: 3 additions & 3 deletions ktor-io/linux/src/CharsetLinux.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import platform.iconv.*
import platform.posix.*

public actual object Charsets {
public actual val UTF_8: Charset = CharsetIconv("UTF-8")
public actual val ISO_8859_1: Charset = CharsetIconv("ISO-8859-1")
internal val UTF_16: Charset = CharsetIconv(platformUtf16)
public actual val UTF_8: Charset by lazy { CharsetIconv("UTF-8") }
public actual val ISO_8859_1: Charset by lazy { CharsetIconv("ISO-8859-1") }
internal val UTF_16: Charset by lazy { CharsetIconv(platformUtf16) }
}

internal actual fun findCharset(name: String): Charset {
Expand Down
6 changes: 3 additions & 3 deletions ktor-io/mingwX64/src/CharsetMingw.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import platform.iconv.*
import platform.posix.*

public actual object Charsets {
public actual val UTF_8: Charset = CharsetIconv("UTF-8")
public actual val ISO_8859_1: Charset = CharsetIconv("ISO-8859-1")
internal val UTF_16: Charset = CharsetIconv(platformUtf16)
public actual val UTF_8: Charset by lazy { CharsetIconv("UTF-8") }
public actual val ISO_8859_1: Charset by lazy { CharsetIconv("ISO-8859-1") }
internal val UTF_16: Charset by lazy { CharsetIconv(platformUtf16) }
}

private class CharsetIconv(name: String) : Charset(name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,11 @@ public interface ABoundSocket {
*/
public interface Acceptable<out S : ASocket> : ASocket {
/**
* accepts socket connection or suspends if none yet available.
* Suspends until a connection is available and returns it or throws if something
* goes wrong.
*
* @return accepted socket
* @throws IOException
*/
public suspend fun accept(): S
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class SwaggerConfig {
/**
* Specifies a Swagger UI version to use.
*/
public var version: String = "4.14.0"
public var version: String = "5.17.12"

/**
* Specifies a URL for a custom CSS applied to a Swagger UI.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ class SwaggerTest {
<html>
<head>
<title>Swagger UI</title>
<link href="https://unpkg.com/swagger-ui-dist@4.14.0/swagger-ui.css" rel="stylesheet">
<link href="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui.css" rel="stylesheet">
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@4.14.0/swagger-ui-bundle.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/swagger-ui-dist@4.14.0/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-bundle.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
<script>window.onload = function() {
window.ui = SwaggerUIBundle({
url: '/swagger/documentation.yaml',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,135 +12,132 @@ import io.ktor.server.plugins.conditionalheaders.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.testing.*
import io.ktor.util.*
import kotlin.test.*

@Suppress("DEPRECATION")
class WebjarsTest {

@Test
fun resourceNotFound() {
withTestApplication {
application.install(Webjars)
handleRequest(HttpMethod.Get, "/webjars/foo.js").let { call ->
testApplication {
install(Webjars)
client.get("/webjars/foo.js").let { response ->
// Should be handled by some other routing
assertEquals(HttpStatusCode.NotFound, call.response.status())
assertEquals(HttpStatusCode.NotFound, response.status)
}
}
}

@Test
fun pathLike() {
withTestApplication {
application.install(Webjars)
application.routing {
testApplication {
install(Webjars)
routing {
get("/webjars-something/jquery") {
call.respondText { "Something Else" }
}
}
handleRequest(HttpMethod.Get, "/webjars-something/jquery").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("Something Else", call.response.content)
client.get("/webjars-something/jquery").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals("Something Else", response.bodyAsText())
}
}
}

@Test
fun nestedPath() {
withTestApplication {
application.install(Webjars) {
testApplication {
install(Webjars) {
path = "/assets/webjars"
}
handleRequest(HttpMethod.Get, "/assets/webjars/jquery/jquery.js").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
client.get("/assets/webjars/jquery/jquery.js").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}

@Test
fun rootPath() {
withTestApplication {
application.install(Webjars) {
testApplication {
install(Webjars) {
path = "/"
}
handleRequest(HttpMethod.Get, "/jquery/jquery.js").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
client.get("/jquery/jquery.js").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}

@Test
fun rootPath2() {
withTestApplication {
application.install(Webjars) {
testApplication {
install(Webjars) {
path = "/"
}
application.routing {
routing {
get("/") { call.respondText("Hello, World") }
}
handleRequest(HttpMethod.Get, "/").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("Hello, World", call.response.content)
client.get("/").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals("Hello, World", response.bodyAsText())
}
handleRequest(HttpMethod.Get, "/jquery/jquery.js").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
client.get("/jquery/jquery.js").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}

@Test
fun versionAgnostic() {
withTestApplication {
application.install(Webjars)
testApplication {
install(Webjars)

handleRequest(HttpMethod.Get, "/webjars/jquery/jquery.js").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
client.get("/webjars/jquery/jquery.js").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}

@Test
fun withGetParameters() {
withTestApplication {
application.install(Webjars)
testApplication {
install(Webjars)

handleRequest(HttpMethod.Get, "/webjars/jquery/jquery.js?param1=value1").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
client.get("/webjars/jquery/jquery.js?param1=value1").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}

@Test
fun withSpecificVersion() {
withTestApplication {
application.install(Webjars)
testApplication {
install(Webjars)

handleRequest(HttpMethod.Get, "/webjars/jquery/3.6.4/jquery.js").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
client.get("/webjars/jquery/3.6.4/jquery.js").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}

@Test
fun withConditionalHeaders() {
withTestApplication {
application.install(Webjars)
application.install(ConditionalHeaders)
handleRequest(HttpMethod.Get, "/webjars/jquery/3.6.4/jquery.js").let { call ->
assertEquals(HttpStatusCode.OK, call.response.status())
assertEquals("application/javascript", call.response.headers["Content-Type"])
assertNotNull(call.response.headers["Last-Modified"])
fun withConditionalAndCachingHeaders() {
testApplication {
install(Webjars)
install(ConditionalHeaders)
client.get("/webjars/jquery/3.6.4/jquery.js").let { response ->
assertEquals(HttpStatusCode.OK, response.status)
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
assertNotNull(response.headers["Last-Modified"])
}
}
}

@OptIn(InternalAPI::class)
@Test
fun callHandledBeforeWebjars() {
val alwaysRespondHello = object : Hook<Unit> {
Expand All @@ -161,7 +158,7 @@ class WebjarsTest {
val response = client.get("/webjars/jquery/3.3.1/jquery.js")
assertEquals(HttpStatusCode.OK, response.status)
assertEquals("Hello", response.bodyAsText())
assertNotEquals("application/javascript", response.headers["Content-Type"])
assertNotEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
}
}
}
Empty file.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Loading

0 comments on commit c22735c

Please sign in to comment.