Skip to content

Commit c22735c

Browse files
authored
Release 2.3.12 (#4088)
1 parent b5d9213 commit c22735c

File tree

18 files changed

+141
-85
lines changed

18 files changed

+141
-85
lines changed

.github/ISSUE_TEMPLATE/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ blank_issues_enabled: false
22
contact_links:
33
- name: Create
44
url: https://youtrack.jetbrains.com/newIssue?project=KTOR
5-
about: Please report any new issue using youtrack
5+
about: Please report any new issues to the JetBrains YouTrack

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# 2.3.12
2+
> Published 20 June 2024
3+
4+
### Bugfixes
5+
* NoSuchMethodError when using coroutines 1.9.0-RC ([KTOR-7054](https://youtrack.jetbrains.com/issue/KTOR-7054))
6+
* Server: Content-Type header for static js, css and svg resources misses charset ([KTOR-6655](https://youtrack.jetbrains.com/issue/KTOR-6655))
7+
* Embedded Linux device without iso-8859-1 and UTF-16 cannot use ktor-network ([KTOR-7016](https://youtrack.jetbrains.com/issue/KTOR-7016))
8+
9+
### Improvements
10+
* Update netty to 4.1.111.Final ([KTOR-7094](https://youtrack.jetbrains.com/issue/KTOR-7094))
11+
* Update netty due to CVE-2024-29025 ([KTOR-7014](https://youtrack.jetbrains.com/issue/KTOR-7014))
12+
* Update dependency on swagger ([KTOR-7019](https://youtrack.jetbrains.com/issue/KTOR-7019))
13+
114
# 2.3.11
215
> Published 8 May 2024
316

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ ktor.ide.jvmAndCommonOnly=true
1010
kotlin.code.style=official
1111

1212
# config
13-
version=2.3.10
13+
version=2.3.12
1414

1515
# gradle
1616
org.gradle.daemon=true

gradle/libs.versions.toml

+11-11
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ serialization-version = "1.5.1"
77
validator-version = "0.8.0"
88
ktlint-version = "3.15.0"
99

10-
netty-version = "4.1.106.Final"
11-
netty-tcnative-version = "2.0.62.Final"
10+
netty-version = "4.1.111.Final"
11+
netty-tcnative-version = "2.0.65.Final"
1212

13-
jetty-version = "9.4.53.v20231009"
14-
jetty-jakarta-version = "11.0.20"
13+
jetty-version = "9.4.54.v20240208"
14+
jetty-jakarta-version = "11.0.21"
1515
jetty-alpn-api-version = "1.1.3.v20160715"
1616
jetty-alpn-boot-version = "8.1.13.v20181017"
17-
jetty-alpn-openjdk8 = "9.4.53.v20231009"
17+
jetty-alpn-openjdk8 = "9.4.54.v20240208"
1818

19-
tomcat-version = "9.0.85"
19+
tomcat-version = "9.0.89"
2020
tomcat-jakarta-version = "10.1.18"
2121

2222
apache-version = "4.1.5"
@@ -30,10 +30,10 @@ gson-version = "2.10.1"
3030
jackson-version = "2.16.1"
3131

3232
junit-version = "4.13.2"
33-
slf4j-version = "2.0.11"
33+
slf4j-version = "2.0.13"
3434
logback-version = "1.3.14"
3535

36-
dropwizard-version = "4.2.25"
36+
dropwizard-version = "4.2.26"
3737
micrometer-version = "1.12.4"
3838

3939
jansi-version = "2.4.1"
@@ -44,8 +44,8 @@ mockk-version = "1.13.5"
4444
java-jwt-version = "4.4.0"
4545

4646
jwks-rsa-version = "0.22.1"
47-
mustache-version = "0.9.11"
48-
freemarker-version = "2.3.32"
47+
mustache-version = "0.9.13"
48+
freemarker-version = "2.3.33"
4949
pebble-version = "3.2.2"
5050
velocity-version = "2.3"
5151
velocity-tools-version = "3.1"
@@ -63,7 +63,7 @@ yamlkt-version = "0.13.0"
6363

6464
swagger-codegen-version = "3.0.41"
6565
swagger-codegen-generators-version = "1.0.38"
66-
swagger-parser-version = "2.1.19"
66+
swagger-parser-version = "2.1.22"
6767

6868
[libraries]
6969
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin-version" }

ktor-http/common/src/io/ktor/http/FileContentType.kt

+24-1
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,34 @@ private val extensionsByContentType: Map<ContentType, List<String>> by lazy {
6565
internal fun List<ContentType>.selectDefault(): ContentType {
6666
val contentType = firstOrNull() ?: ContentType.Application.OctetStream
6767
return when {
68-
contentType.contentType == "text" && contentType.charset() == null -> contentType.withCharset(Charsets.UTF_8)
68+
contentType.match(ContentType.Text.Any) -> contentType.withCharsetUTF8IfNeeded()
69+
contentType.match(ContentType.Image.SVG) -> contentType.withCharsetUTF8IfNeeded()
70+
contentType.matchApplicationTypeWithCharset() -> contentType.withCharsetUTF8IfNeeded()
6971
else -> contentType
7072
}
7173
}
7274

75+
private fun ContentType.matchApplicationTypeWithCharset(): Boolean {
76+
if (!match(ContentType.Application.Any)) return false
77+
78+
return when {
79+
match(ContentType.Application.Atom) ||
80+
match(ContentType.Application.JavaScript) ||
81+
match(ContentType.Application.Rss) ||
82+
match(ContentType.Application.Xml) ||
83+
match(ContentType.Application.Xml_Dtd)
84+
-> true
85+
86+
else -> false
87+
}
88+
}
89+
90+
private fun ContentType.withCharsetUTF8IfNeeded(): ContentType {
91+
if (charset() != null) return this
92+
93+
return withCharset(Charsets.UTF_8)
94+
}
95+
7396
internal fun <A, B> Sequence<Pair<A, B>>.groupByPairs() = groupBy { it.first }
7497
.mapValues { e -> e.value.map { it.second } }
7598

ktor-http/common/src/io/ktor/http/Mimes.kt

+1
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ private val rawMimes: String
428428
.jpgv,video/jpeg
429429
.jpm,video/jpm
430430
.jps,image/x-jps
431+
.js,text/javascript
431432
.js,application/javascript
432433
.json,application/json
433434
.jut,image/jutvision

ktor-io/linux/src/CharsetLinux.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import platform.iconv.*
1010
import platform.posix.*
1111

1212
public actual object Charsets {
13-
public actual val UTF_8: Charset = CharsetIconv("UTF-8")
14-
public actual val ISO_8859_1: Charset = CharsetIconv("ISO-8859-1")
15-
internal val UTF_16: Charset = CharsetIconv(platformUtf16)
13+
public actual val UTF_8: Charset by lazy { CharsetIconv("UTF-8") }
14+
public actual val ISO_8859_1: Charset by lazy { CharsetIconv("ISO-8859-1") }
15+
internal val UTF_16: Charset by lazy { CharsetIconv(platformUtf16) }
1616
}
1717

1818
internal actual fun findCharset(name: String): Charset {

ktor-io/mingwX64/src/CharsetMingw.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import platform.iconv.*
1010
import platform.posix.*
1111

1212
public actual object Charsets {
13-
public actual val UTF_8: Charset = CharsetIconv("UTF-8")
14-
public actual val ISO_8859_1: Charset = CharsetIconv("ISO-8859-1")
15-
internal val UTF_16: Charset = CharsetIconv(platformUtf16)
13+
public actual val UTF_8: Charset by lazy { CharsetIconv("UTF-8") }
14+
public actual val ISO_8859_1: Charset by lazy { CharsetIconv("ISO-8859-1") }
15+
internal val UTF_16: Charset by lazy { CharsetIconv(platformUtf16) }
1616
}
1717

1818
private class CharsetIconv(name: String) : Charset(name) {

ktor-network/jvmAndNix/src/io/ktor/network/sockets/Sockets.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ public interface ABoundSocket {
6666
*/
6767
public interface Acceptable<out S : ASocket> : ASocket {
6868
/**
69-
* accepts socket connection or suspends if none yet available.
69+
* Suspends until a connection is available and returns it or throws if something
70+
* goes wrong.
71+
*
7072
* @return accepted socket
73+
* @throws IOException
7174
*/
7275
public suspend fun accept(): S
7376
}

ktor-server/ktor-server-plugins/ktor-server-swagger/jvm/src/io/ktor/server/plugins/swagger/SwaggerConfig.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class SwaggerConfig {
1313
/**
1414
* Specifies a Swagger UI version to use.
1515
*/
16-
public var version: String = "4.14.0"
16+
public var version: String = "5.17.12"
1717

1818
/**
1919
* Specifies a URL for a custom CSS applied to a Swagger UI.

ktor-server/ktor-server-plugins/ktor-server-swagger/jvm/test/io/ktor/server/plugins/swagger/SwaggerTest.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ class SwaggerTest {
2424
<html>
2525
<head>
2626
<title>Swagger UI</title>
27-
<link href="https://unpkg.com/swagger-ui-dist@4.14.0/swagger-ui.css" rel="stylesheet">
27+
<link href="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui.css" rel="stylesheet">
2828
</head>
2929
<body>
3030
<div id="swagger-ui"></div>
31-
<script src="https://unpkg.com/swagger-ui-dist@4.14.0/swagger-ui-bundle.js" crossorigin="anonymous"></script>
32-
<script src="https://unpkg.com/swagger-ui-dist@4.14.0/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
31+
<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-bundle.js" crossorigin="anonymous"></script>
32+
<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
3333
<script>window.onload = function() {
3434
window.ui = SwaggerUIBundle({
3535
url: '/swagger/documentation.yaml',

ktor-server/ktor-server-plugins/ktor-server-webjars/jvm/test/io/ktor/server/webjars/WebjarsTest.kt

+53-56
Original file line numberDiff line numberDiff line change
@@ -12,135 +12,132 @@ import io.ktor.server.plugins.conditionalheaders.*
1212
import io.ktor.server.response.*
1313
import io.ktor.server.routing.*
1414
import io.ktor.server.testing.*
15-
import io.ktor.util.*
1615
import kotlin.test.*
1716

18-
@Suppress("DEPRECATION")
1917
class WebjarsTest {
2018

2119
@Test
2220
fun resourceNotFound() {
23-
withTestApplication {
24-
application.install(Webjars)
25-
handleRequest(HttpMethod.Get, "/webjars/foo.js").let { call ->
21+
testApplication {
22+
install(Webjars)
23+
client.get("/webjars/foo.js").let { response ->
2624
// Should be handled by some other routing
27-
assertEquals(HttpStatusCode.NotFound, call.response.status())
25+
assertEquals(HttpStatusCode.NotFound, response.status)
2826
}
2927
}
3028
}
3129

3230
@Test
3331
fun pathLike() {
34-
withTestApplication {
35-
application.install(Webjars)
36-
application.routing {
32+
testApplication {
33+
install(Webjars)
34+
routing {
3735
get("/webjars-something/jquery") {
3836
call.respondText { "Something Else" }
3937
}
4038
}
41-
handleRequest(HttpMethod.Get, "/webjars-something/jquery").let { call ->
42-
assertEquals(HttpStatusCode.OK, call.response.status())
43-
assertEquals("Something Else", call.response.content)
39+
client.get("/webjars-something/jquery").let { response ->
40+
assertEquals(HttpStatusCode.OK, response.status)
41+
assertEquals("Something Else", response.bodyAsText())
4442
}
4543
}
4644
}
4745

4846
@Test
4947
fun nestedPath() {
50-
withTestApplication {
51-
application.install(Webjars) {
48+
testApplication {
49+
install(Webjars) {
5250
path = "/assets/webjars"
5351
}
54-
handleRequest(HttpMethod.Get, "/assets/webjars/jquery/jquery.js").let { call ->
55-
assertEquals(HttpStatusCode.OK, call.response.status())
56-
assertEquals("application/javascript", call.response.headers["Content-Type"])
52+
client.get("/assets/webjars/jquery/jquery.js").let { response ->
53+
assertEquals(HttpStatusCode.OK, response.status)
54+
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
5755
}
5856
}
5957
}
6058

6159
@Test
6260
fun rootPath() {
63-
withTestApplication {
64-
application.install(Webjars) {
61+
testApplication {
62+
install(Webjars) {
6563
path = "/"
6664
}
67-
handleRequest(HttpMethod.Get, "/jquery/jquery.js").let { call ->
68-
assertEquals(HttpStatusCode.OK, call.response.status())
69-
assertEquals("application/javascript", call.response.headers["Content-Type"])
65+
client.get("/jquery/jquery.js").let { response ->
66+
assertEquals(HttpStatusCode.OK, response.status)
67+
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
7068
}
7169
}
7270
}
7371

7472
@Test
7573
fun rootPath2() {
76-
withTestApplication {
77-
application.install(Webjars) {
74+
testApplication {
75+
install(Webjars) {
7876
path = "/"
7977
}
80-
application.routing {
78+
routing {
8179
get("/") { call.respondText("Hello, World") }
8280
}
83-
handleRequest(HttpMethod.Get, "/").let { call ->
84-
assertEquals(HttpStatusCode.OK, call.response.status())
85-
assertEquals("Hello, World", call.response.content)
81+
client.get("/").let { response ->
82+
assertEquals(HttpStatusCode.OK, response.status)
83+
assertEquals("Hello, World", response.bodyAsText())
8684
}
87-
handleRequest(HttpMethod.Get, "/jquery/jquery.js").let { call ->
88-
assertEquals(HttpStatusCode.OK, call.response.status())
89-
assertEquals("application/javascript", call.response.headers["Content-Type"])
85+
client.get("/jquery/jquery.js").let { response ->
86+
assertEquals(HttpStatusCode.OK, response.status)
87+
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
9088
}
9189
}
9290
}
9391

9492
@Test
9593
fun versionAgnostic() {
96-
withTestApplication {
97-
application.install(Webjars)
94+
testApplication {
95+
install(Webjars)
9896

99-
handleRequest(HttpMethod.Get, "/webjars/jquery/jquery.js").let { call ->
100-
assertEquals(HttpStatusCode.OK, call.response.status())
101-
assertEquals("application/javascript", call.response.headers["Content-Type"])
97+
client.get("/webjars/jquery/jquery.js").let { response ->
98+
assertEquals(HttpStatusCode.OK, response.status)
99+
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
102100
}
103101
}
104102
}
105103

106104
@Test
107105
fun withGetParameters() {
108-
withTestApplication {
109-
application.install(Webjars)
106+
testApplication {
107+
install(Webjars)
110108

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

118116
@Test
119117
fun withSpecificVersion() {
120-
withTestApplication {
121-
application.install(Webjars)
118+
testApplication {
119+
install(Webjars)
122120

123-
handleRequest(HttpMethod.Get, "/webjars/jquery/3.6.4/jquery.js").let { call ->
124-
assertEquals(HttpStatusCode.OK, call.response.status())
125-
assertEquals("application/javascript", call.response.headers["Content-Type"])
121+
client.get("/webjars/jquery/3.6.4/jquery.js").let { response ->
122+
assertEquals(HttpStatusCode.OK, response.status)
123+
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
126124
}
127125
}
128126
}
129127

130128
@Test
131-
fun withConditionalHeaders() {
132-
withTestApplication {
133-
application.install(Webjars)
134-
application.install(ConditionalHeaders)
135-
handleRequest(HttpMethod.Get, "/webjars/jquery/3.6.4/jquery.js").let { call ->
136-
assertEquals(HttpStatusCode.OK, call.response.status())
137-
assertEquals("application/javascript", call.response.headers["Content-Type"])
138-
assertNotNull(call.response.headers["Last-Modified"])
129+
fun withConditionalAndCachingHeaders() {
130+
testApplication {
131+
install(Webjars)
132+
install(ConditionalHeaders)
133+
client.get("/webjars/jquery/3.6.4/jquery.js").let { response ->
134+
assertEquals(HttpStatusCode.OK, response.status)
135+
assertEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
136+
assertNotNull(response.headers["Last-Modified"])
139137
}
140138
}
141139
}
142140

143-
@OptIn(InternalAPI::class)
144141
@Test
145142
fun callHandledBeforeWebjars() {
146143
val alwaysRespondHello = object : Hook<Unit> {
@@ -161,7 +158,7 @@ class WebjarsTest {
161158
val response = client.get("/webjars/jquery/3.3.1/jquery.js")
162159
assertEquals(HttpStatusCode.OK, response.status)
163160
assertEquals("Hello", response.bodyAsText())
164-
assertNotEquals("application/javascript", response.headers["Content-Type"])
161+
assertNotEquals(ContentType.Text.JavaScript, response.contentType()?.withoutParameters())
165162
}
166163
}
167164
}

ktor-server/ktor-server-tests/jvm/test-resources/public/types/file.css

Whitespace-only changes.

ktor-server/ktor-server-tests/jvm/test-resources/public/types/file.js

Whitespace-only changes.

ktor-server/ktor-server-tests/jvm/test-resources/public/types/file.svg

Loading

ktor-server/ktor-server-tests/jvm/test-resources/public/types/file.xml

Whitespace-only changes.

0 commit comments

Comments
 (0)