Changelog 1.6 version
1.6.8
released 15th March 2022
Client
WebSocket client closes connection due to an HTTP request timeout
This broke between 2.0.1 and 2.0.2.
val websocketClient = HttpClient(CIO) {
install(HttpTimeout) {
connectTimeoutMillis = 2000L
}
install(WebSockets) {
pingInterval = 30000L
}
}
val session = websocketClient.webSocketSession("ws://some-url")
session.launch {
while (isActive) {
val frame = session.incoming.receive()
// to things with frame
}
}
The websocket server shows the client as connected and eventually reports an abnormal close. On the client side the coroutine is cancelled with a request timeout exception from ktor:
java.util.concurrent.CancellationException: Request is timed out
at kotlinx.coroutines.ExceptionsKt.CancellationException(Exceptions.kt:22)
at kotlinx.coroutines.JobKt__JobKt.cancel(Job.kt:596)
at kotlinx.coroutines.JobKt.cancel(Unknown Source)
at io.ktor.client.engine.cio.EndpointKt$setupTimeout$timeoutJob$1.invokeSuspend(Endpoint.kt:250)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Caused by: io.ktor.client.plugins.HttpRequestTimeoutException: Request timeout has expired [url=ws://mrf-rest.lab2018.qa.lbaum.eu:8081/v2/events/3853126682810736, request_timeout=unknown ms]
... 7 common frames omitted
Darwin and Kotlin/JS: "List has more than one element" error when header like Content-type is duplicated in a response
When I try to fetch html and analyze it in Multiplatform Mobile share lib, I got a crash in iOS, but work well in Android.
iOS error msg: IllegalArgumentException("List has more than one element.")
URL: https://mp.weixin.qq.com/s/UJipNKgGPzZ1iPJBAaLJXw
so I compile the ktor source code and debug inside, and then I foud out the reason is that the response header "content-type" has a repeated key-value entry,As shown below:
In this case, iOS native network lib will merge them into one key-value entry like {"content-type" : "text/html; charset=UTF-8 , text/html; charset=UTF-8" } .
But on the other hand, ContentType.parse() will parse "content-type" header and get two HeaderValue, after that it invoke Colloection.single() to check the result, then a IllegalArgumentException("List has more than one element.") will be throw.
I checked the implementation of other platforms,browserjs have the same issue.
Refresh token is failing on redirect
I'm using the Ktor Client Auth feature with bearer tokens. But the refresh token is failing when a 302 redirect is involved.
My issue is as follow:
-I have an invalid token, let's call this token A
-I issue a GET /news/latest request with the invalid token A
-The backend replies with a 401 and the WWW-Authenticate header
-My refreshTokens block is executed and I get a new valid token, let's call this token B
-Ktor retries the previous GET /news/latest with the new token B
-Now the issue is that the backend replies with a redirect 302 /news/123
-Ktor follows the redirect and emits a GET /news/123 but this call is sent with the invalid token A
Everything is working correctly if there is no 302 redirect. Should I be doing something different for this use case to work?
Websocket error: "SunCertPathBuilderException: unable to find valid certification path to requested target"
I'm trying to connect to a server using a websocket, but I run into the following error: "SunCertPathBuilderException: unable to find valid certification path to requested target". I've tested the connection ("wss://acme.com/connect") with Postman and with PieSocket where everything seems to be working.
I'm using the following code:
val client = HttpClient {
install(WebSockets)
}
runBlocking {
client.wss(
host = "acme.com"
) {
val messageOutputRoutine = launch {
try {
for (message in incoming) {
message as? Frame.Text ?: continue
println(message.readText())
}
} catch (e: Exception) {
println("Error while receiving: " + e.localizedMessage)
}
}
// Wait for completion; either "exit" or error.
messageOutputRoutine.join()
}
}
client.close()
Thanks in advance!
Ktor http client with java engine uses incorrect timeout.
When Ktor creates a java.net.http.HttpRequest
it uses HttpTimeout.socketTimeoutMillis
to set HttpRequest.timeout
. But in java docs it's clear that HttpRequest.timeout
sets timeout for whole request, not for time without any data in a socket, so it's better to use HttpTimeout.requestTimeoutMillis
for that.
Place in ktor code where ktor sets HttpRequest.timeout
Docs
Broken link in docs for Ktor Testing
The link in the screenshot (https://ktor.io/docs/old/testing.html#map) attached goes to the following url which is a 404
JMXReporter not included in ktor-metrics:1.6.8
According to the documentation the JmxReporter
should be included in the metrics-jmx
dependency, but that doesn't appear to be the case in version 1.6.8
. I had to manually add the dependency to "io.dropwizard.metrics:metrics-jmx:4.2.9" instead.
IntelliJ IDEA Plugin
A table with test methods should span the entire width of the dialog
IntelliJ IDEA 2022.1 Beta (Ultimate Edition)
The plugin doesn't add the 'org.jetbrains.kotlin:kotlin-test' dependency when generating a test
The plugin generates red tests
- Open the
codeSnippets
project as described here: https://github.com/ktorio/ktor-documentation/blob/main/codeSnippets/README.md - Open the
post
module: https://github.com/ktorio/ktor-documentation/tree/main/codeSnippets/snippets/post - Place the caret at
Application.main
, press Alt+Enter, and chooseGenerate test for Ktor module
. - Click
Create
in the invoked dialog.
=>MainTest.kt
code is red
Server
java.lang.StackOverflowError in logger on KTor 1.3.4
Services on ktor 1.3.4 are logging sometimes
java.lang.StackOverflowError: null
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:54)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:72)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:72)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:72)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:72)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:72)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:72)
which might be related to https://github.com/Kotlin/kotlinx.coroutines/issues/1264,
however I can't find a place where JobCancellationException might have been caught and wrapped in another exception.
Route that is logging this is not doing anything in parallel.
This is only happening on ktor 1.3.4, never seen on earlier versions.
Shared
support receive ReadChannelContent on ktor server and client
To share more models between client and server, it would be awesome, if ktor server and client could support ReadChannelContent on receiving data. Right now I use custom plugins for that:
// for server
val ByteReadChannelToReadChannelContent = createRouteScopedPlugin("ByteReadChannelToReadChannelContent") {
onCallReceive { call ->
val requestedType = call.receiveType
if (requestedType.type != OutgoingContent.ReadChannelContent::class) return@onCallReceive
transformBody { body ->
object : OutgoingContent.ReadChannelContent() {
override fun readFrom() = body
override val contentLength = call.request.contentLength()
override val contentType = call.request.contentType()
}
}
}
}
// for client
object ByteReadChannelToReadChannelContent : HttpClientPlugin<Unit, Unit> {
override val key: AttributeKey<Unit> = AttributeKey("ByteReadChannelToReadChannelContent")
override fun prepare(block: Unit.() -> Unit) {
}
override fun install(plugin: Unit, scope: HttpClient) {
scope.responsePipeline.intercept(HttpResponsePipeline.Transform) { (info, body) ->
if (body !is ByteReadChannel || info.type != OutgoingContent.ReadChannelContent::class) return@intercept
proceedWith(HttpResponseContainer(info,
object : OutgoingContent.ReadChannelContent() {
override fun readFrom(): ByteReadChannel = body
override val contentType = context.response.contentType()
override val contentLength = context.response.contentLength()
}
))
}
}
}
Other
Update to Kotlin 1.6.20
Split packages in KTOR Client 2.00-BETA-1
Ive seen alot of fixed issues about module system support in ktor, but right out of the box using the client-cio there are errors being thrown about split packages between both 'ktor.client.cio.jvm' and 'ktor.client.core.jvm' due to package 'io.ktor.client.plugins.websocket' in Java 17. Im using Gradle and the dependency: 'io.ktor:ktor-client-cio:2.0.0-beta-1'. Thanks!
Support WebSockets in Darwin engine
Netty's I/O operation failed debug message is logged
Ktor version 2.0.0-beta-1
, engine Netty
Kotlin version 1.6.10
JDK 11
I have a simple POST
request in my router
Whenever I send requests to that route using IntelliJ IDEA's http client, I get this debug message printed out (thought I get correct response)
2022-03-31 16:34:12.596 [eventLoopGroupProxy-3-2] DEBUG Application - I/O operation failed
java.io.IOException: Connection reset by peer
at java.base/sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at java.base/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at java.base/sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:276)
at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:233)
at java.base/sun.nio.ch.IOUtil.read(IOUtil.java:223)
at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:358)
at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:253)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda-1$lambda-0(NettyApplicationEngine.kt:258)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
That happens with all HTTP methods — GET
, POST
, etc
That doesn't happen when I use Postman or cUrl.
My request is
POST http://127.0.0.1:8080/test
Content-Type: application/json
{
"testKey1": "testVal1",
}
Youtrack: Add 1.6.8
Backpost fix to 1.6.7. : Provides transitive vulnerable dependency ch.qos.logback:logback-classic:1.2.6, logback-core, jetty-http
testImplementation("io.ktor:ktor-server-tests:1.6.7")
leads to:
Provides transitive vulnerable dependency ch.qos.logback:logback-classic:1.2.6 Deserialization of Untrusted Data vulnerability pending CVSS allocation
Provides transitive vulnerable dependency ch.qos.logback:logback-core:1.2.6 Deserialization of Untrusted Data vulnerability pending CVSS allocation
Provides transitive vulnerable dependency org.eclipse.jetty:jetty-http:9.4.42.v20210604 Exposure of Sensitive Information to an Unauthorized Actor vulnerability pending CVSS allocation
https://advisory.checkmarx.net/advisory/vulnerability/CVE-2021-42550
1.6.7
released 8th December 2021
Client
CIO client bidirectional streaming
I'm working on a project which requires a client to stream a potentially large amount of binary data to a server and receive a stream in response. Because the client to server stream could be very long, I need to be able to read the response on the client side before the client has completed sending. From my testing, this does not appear to be possible using the CIO client.
Here is a small example which illustrates the limitation:
suspend fun main() {
runServer()
runClient()
}
suspend fun runServer() {
embeddedServer(Netty, port = 8763) {
routing {
post("/post") {
launch { readChannel("Server", call.receiveChannel()) }
launch { call.respond(createContent("Server")) }
}
}
}.also { it.start(false) }
}
suspend fun runClient() {
HttpClient(CIO).request<HttpStatement> {
url("http://localhost:8763/post")
method = HttpMethod.Post
body = createContent("Client")
}.execute { readChannel("Client", it.receive()) }
}
fun createContent(name: String) = createContent {
repeat(3) {
println("$name: Sending ${BYTES.size} bytes")
writeFully(BYTES)
flush()
delay(1000)
}
}
fun createContent(body: suspend ByteWriteChannel.() -> Unit) =
ChannelWriterContent(body, null)
suspend fun readChannel(name: String, channel: ByteReadChannel) {
val buffer = ByteArray(BYTES.size)
while (true) {
try { channel.readFully(buffer) }
catch(e: Exception) { break }
println("$name: Read ${buffer.size} bytes")
}
}
Running the above sample produces the following output:
Client: Sending 1024 bytes
Server: Read 1024 bytes
Server: Sending 1024 bytes
Client: Sending 1024 bytes
Server: Read 1024 bytes
Server: Sending 1024 bytes
Client: Sending 1024 bytes
Server: Read 1024 bytes
Server: Sending 1024 bytes
Client: Read 1024 bytes
Client: Read 1024 bytes
Client: Read 1024 bytes
As you can see, the client reads occur after all client sends which is not acceptable for my use case. Ideally, the output would look like this:
Client: Sending 1024 bytes
Server: Read 1024 bytes
Server: Sending 1024 bytes
Client: Read 1024 bytes
Client: Sending 1024 bytes
Server: Read 1024 bytes
Server: Sending 1024 bytes
Client: Read 1024 bytes
Client: Sending 1024 bytes
Server: Read 1024 bytes
Server: Sending 1024 bytes
Client: Read 1024 bytes
From what I can tell, it seems the HttpStatement.execute
method blocks until the client has sent it's entire payload.
[iOS] Prevent HttpClient from persisting cookies across requests
Hello!
I'm using Ktor in a KMM app, and I am not having any kind of problem in Android, but in iOS it behaves weird. I don't have the HttpCookies plugin installed, because I'm handling and storing the session cookie outside of Ktor.
What happens is that the very first request that is sent to the server (GET /api/session
) contains a Set-Cookie
header in the response, and for this request I don't save the cookie nor do anything with it, the request serves only to check if there is a session based solely on the response of the server. Both in Android and iOS we get the Set-Cookie
header for this request.
The second request (POST /api/session
) is made after the user attempts to log in using their credentials. For this request, we need the response to contain the Set-Cookie
header so we can store the session token it contains and then pass it onto further requests. This happens in Android, but not in iOS. I tried removing the first request, and magically, I get a cookie for this one!
Is the iOS backend automatically storing and passing the cookie without my knowledge or consent? As I said before, I didn't install the HttpCookies plugin.
Automatic addition of ; charset=UTF-8 to Content-Type header can "break" badly designed existing REST APIs
Ktor client appears to automatically add ; charset=UTF-8
to text-based content type requests, for example even if you set the Content-Type explicity to (say) application/json
the Ktor client appends `; charset=UTF-8'.
Unfortunately some existing APIs check explicity for Content-Type=application/json
to determine if the request is a valid content type. An example of this (arguably naive) behaviour is the UK-based Esendex SMS REST API, see https://developers.esendex.com/api-reference#messagedispatcher which responds with 400 Bad request; message: Unable to process request body
I'm not familar with the Ktor code base, but a quick search reveals the code which adds the ; charset=UTF-8
may be in ApplicationResponseFunctions, or maybe its request equivalent?
/**
* Creates a default [ContentType] based on the given [contentType] and current call
*
* If [contentType] is null, it tries to fetch already set response header "Content-Type". If the header is not available
* `text/plain` is used. If [contentType] is specified, it uses it
*
* Additionally, if charset is not set for either content type, it appends `; charset=UTF-8` to the content type.
*/
public fun ApplicationCall.defaultTextContentType(contentType: ContentType?): ContentType {
val result = when (contentType) {
null -> {
val headersContentType = response.headers[HttpHeaders.ContentType]
headersContentType?.let {
try {
ContentType.parse(headersContentType)
} catch (_: BadContentTypeFormatException) {
null
}
} ?: ContentType.Text.Plain
}
else -> contentType
}
return if (result.charset() == null) {
result.withCharset(Charsets.UTF_8)
} else {
result
}
}
HttpResponseValidator.handleResponseException should have access to request to provide valuable information in exceptions
I'm mapping a common Exception format in our app, but currently there is no way to get the request in the handleResponseException
method. We just have access to the exception.
This limits my ability to pass information back about the exception completely. When I get a crash report on iOS or even on Android sometimes, I'm left with no information about where this crash is coming from (as it's an asyncronous request, and the caller isn't in the callstack). If I had the ability to at least include information about what request is failing, I could track down everywhere this is being used and better find the crash. As it is now, I've got almost no information to go off of.
AcceptAllCookiesStorage cannot find a cookie when DefaultRequest plugin is used
If the path of the cookie starts with /
, but the path of the requestURL does not, AcceptAllCookiesStorage
does not find the cookie in its container
(cookie list).
See attached test and debugger state.
Ktor websockets ping/pong
I have a Netty server with installed WebSockets with pingInterval. After each delay it received PONG message.
Also, I have HttpClient with installed WebSockets on Kotlin/JS side with pingInterval set. But I don't catch any PING messages on server.
How it can be fixed?
Update to support coroutines 1.6.0 to resolve runTest error with native-mt
When using 1.6.7 but forcing coroutines 1.6.0-native-mt, I get test errors on native:
> Task :native-test:nativeTest
com.rnett.krosstalk.native_test.Tests.testBasic STANDARD_OUT
HttpClient: REQUEST: http://localhost:8087/krosstalk/testBasic_k0pcu7
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 16
HttpClient: -> Content-Type: application/octet-stream
HttpClient: BODY Content-Type: application/octet-stream
HttpClient: BODY START
HttpClient: [request body omitted]
HttpClient: BODY END
HttpClient: REQUEST http://localhost:8087/krosstalk/testBasic_k0pcu7 failed with exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlinx.coroutines.internal.ThreadSafeHeap@9ca057b8
com.rnett.krosstalk.native_test.Tests.testBasic FAILED
kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlinx.coroutines.test.TestScopeImpl@9c8bda18
at kfun:kotlin.Throwable#<init>(kotlin.String?;kotlin.Throwable?){} (00007ff7bbddb6f0)
at kfun:kotlin.Throwable#<init>(kotlin.String?){} (00007ff7bbddba20)
at kfun:kotlin.Exception#<init>(kotlin.String?){} (00007ff7bbdd4c80)
at kfun:kotlin.RuntimeException#<init>(kotlin.String?){} (00007ff7bbdd4e30)
at kfun:kotlin.native.concurrent.InvalidMutabilityException#<init>(kotlin.String){} (00007ff7bbe08930)
at ThrowInvalidMutabilityException (00007ff7bbe09d30)
at MutationCheck (00007ff7bc36f6e0)
at kfun:kotlinx.coroutines.test.TestScopeImpl.<set-finished>#internal (00007ff7bc2781c0)
at kfun:kotlinx.coroutines.test.TestScopeImpl#leave(){}kotlin.collections.List<kotlin.Throwable> (00007ff7bc278a90)
at kfun:kotlinx.coroutines.test.runTest$<anonymous>_3$<anonymous>_4#internal (00007ff7bc26dd80)
at kfun:kotlinx.coroutines.test.$runTest$<anonymous>_3$<anonymous>_4$FUNCTION_REFERENCE$18.invoke#internal (00007ff7bc271400)
at kfun:kotlinx.coroutines.test.$runTestCoroutineCOROUTINE$21#invokeSuspend(kotlin.Result<kotlin.Any?>){}kotlin.Any? (00007ff7bc26c490)
at kfun:kotlinx.coroutines.test#runTestCoroutine(0:0;kotlin.Long;kotlin.Function1<0:0,kotlin.Throwable?>;kotlin.coroutines.SuspendFunction1<0:0,kotlin.Unit>;kotlin.Function0<kotlin.collections.List<kotlin.Throwable>>){0�<kotlinx.coroutines.AbstractCoroutine<kotlin.Unit>>} (00007ff7bc26d7b0)
at kfun:kotlinx.coroutines.test.$runTest$<anonymous>_3COROUTINE$22.invokeSuspend#internal (00007ff7bc26dff0)
at kfun:kotlinx.coroutines.test.$runTest$<anonymous>_3COROUTINE$22.invoke#internal (00007ff7bc26e690)
at kfun:kotlinx.coroutines.test.$createTestResult$lambda-0COROUTINE$27.invokeSuspend#internal (00007ff7bc27c610)
at kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} (00007ff7bbdfd700)
at kfun:kotlinx.coroutines.DispatchedTask#run(){} (00007ff7bc066760)
at kfun:kotlinx.coroutines.EventLoopImplBase#processNextEvent(){}kotlin.Long (00007ff7bc0199a0)
at kfun:kotlinx.coroutines#runEventLoop(kotlinx.coroutines.EventLoop?;kotlin.Function0<kotlin.Boolean>){} (00007ff7bc092ca0)
at kfun:kotlinx.coroutines.BlockingCoroutine.joinBlocking#internal (00007ff7bc091bd0)
at kfun:kotlinx.coroutines#runBlocking(kotlin.coroutines.CoroutineContext;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>){0�<kotlin.Any?>}0:0 (00007ff7bc090460)
at kfun:kotlinx.coroutines#runBlocking$default(kotlin.coroutines.CoroutineContext?;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>;kotlin.Int){0�<kotlin.Any?>}0:0 (00007ff7bc090da0)
at kfun:kotlinx.coroutines.test#createTestResult(kotlin.coroutines.SuspendFunction0<kotlin.Unit>){} (00007ff7bc27c3c0)
at kfun:kotlinx.coroutines.test#runTest__at__kotlinx.coroutines.test.TestScope(kotlin.Long;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.test.TestScope,kotlin.Unit>){} (00007ff7bc26c0b0)
2 tests completed, 1 failed
at kfun:kotlinx.coroutines.test#runTest(kotlin.coroutines.CoroutineContext;kotlin.Long;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.test.TestScope,kotlin.Unit>){} (00007ff7bc26b9e0)
at kfun:kotlinx.coroutines.test#runTest$default(kotlin.coroutines.CoroutineContext?;kotlin.Long;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.test.TestScope,kotlin.Unit>;kotlin.Int){} (00007ff7bc26bdb0)
at kfun:com.rnett.krosstalk.native_test.Tests#testBasic(){} (00007ff7bc2c1e20)
at kfun:com.rnett.krosstalk.native_test.$Tests$test$0.$testBasic$FUNCTION_REFERENCE$1.invoke#internal (00007ff7bc2c3410)
at kfun:com.rnett.krosstalk.native_test.$Tests$test$0.$testBasic$FUNCTION_REFERENCE$1.$<bridge-UNNN>invoke(-1:0){}#internal (00007ff7bc2c3600)
at kfun:kotlin.native.internal.test.BaseClassSuite.TestCase#run(){} (00007ff7bbe3d740)
at kfun:kotlin.native.internal.test.TestRunner.run#internal (00007ff7bbe33cd0)
at kfun:kotlin.native.internal.test.TestRunner.runIteration#internal (00007ff7bbe36960)
at kfun:kotlin.native.internal.test.TestRunner#run(){}kotlin.Int (00007ff7bbe38800)
at kfun:kotlin.native.internal.test#testLauncherEntryPoint(kotlin.Array<kotlin.String>){}kotlin.Int (00007ff7bbe29430)
at kfun:kotlin.native.internal.test#main(kotlin.Array<kotlin.String>){} (00007ff7bbe293c0)
at Konan_start (00007ff7bbe295d0)
at Init_and_run_start (00007ff7bc370d30)
at __tmainCRTStartup (00007ff7bbdc1180)
at mainCRTStartup (00007ff7bbdc14f0)
at (00007ffeba697960)
at (00007ffebd1ba2d0)
Full CI logs: https://github.com/rnett/krosstalk/runs/4614376051?check_suite_focus=true
Commit: https://github.com/rnett/krosstalk/tree/1bf335a64f6eb8d3a3b3ec7dbc68568345033907
To reproduce: run ./gradlew :native-test:nativeTest
in the tests
directory.
Would be nice to have an update soon for runTest
support.
ResponseObserver does not respect MDC context
When logging response from. Ktor-client Logging
feature with the help of ResponseObserver
, the log does not contains the MDC context.
This mean when tracking all logs bound to an MDC context, response content log remains untracked.
This test illustrates the mentioned scenario :
in package [jvmTest]io.ktor.client.features.logging
, in file LoggingTest.kt
@Test
fun loggingWithMDCContextTest(): Unit = runBlocking {
val messages: MutableList<String> = mutableListOf()
val testLogger: Logger = object : Logger by LoggerFactory.getLogger("ktor.test") {
override fun trace(message: String?) = add("TRACE: $message")
override fun debug(message: String?) = add("DEBUG: $message")
override fun info(message: String?) = add("INFO: $message")
private fun add(message: String?) {
if (message != null) {
val mdcText = MDC.getCopyOfContextMap()?.let { mdc ->
if (mdc.isNotEmpty()) {
mdc.entries.sortedBy { it.key }
.joinToString(prefix = " [", postfix = "]") { "${it.key}=${it.value}" }
} else {
""
}
} ?: ""
messages.add(message + mdcText)
}
}
}
val localTestLogger: io.ktor.client.features.logging.Logger = object : io.ktor.client.features.logging.Logger {
override fun log(message: String) {
testLogger.info(message)
}
}
val client: HttpClient = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = localTestLogger
// responseCoroutineContext = MDCContext() This is to provide CoroutineContext from feature config
}
}
MDC.put("trace_id", "48b49e15-f7c4-4991-9e33-23850a218718")
val response: String = withContext(MDCContext()) {
client.get("https://jsonplaceholder.typicode.com/todos/1")
}
MDC.clear()
assertNotNull(messages)
assertNotNull(response)
}
Theory : First I suspected that this is because of EmptyCoroutineContext
being used in launch
, but when I gave MDCContext()
from kotlinx-coroutines-slf4j
to it, it still didn't work. Now I suspect, it is because function is provided as a predicate. However, I am not too sure about it. Can you help please ?
Change I tested :
scope.launch(feature.coroutineContext) {
try {
feature.responseHandler(sideCall.response)
} catch (_: Throwable) {
}
val content = sideCall.response.content
if (!content.isClosedForRead) {
content.discard()
}
}
where ResponseObserver = public class ResponseObserver(private val responseHandler: ResponseHandler, private val coroutineContext: CoroutineContext = EmptyCoroutineContext)
Elements of messages :
INFO: REQUEST: https://jsonplaceholder.typicode.com/todos/1 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: METHOD: HttpMethod(value=GET) [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: COMMON HEADERS [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> Accept: */* [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> Accept-Charset: UTF-8 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: CONTENT HEADERS [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> Content-Length: 0 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: BODY Content-Type: null [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: BODY START [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: BODY END [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: RESPONSE: 200 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: METHOD: HttpMethod(value=GET) [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: FROM: https://jsonplaceholder.typicode.com/todos/1 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: COMMON HEADERS [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> access-control-allow-credentials: true [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> age: 5692 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> cache-control: max-age=43200 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> cf-cache-status: HIT [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> cf-ray: 63a05ebc7fdf10f3-CPH [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> cf-request-id: 09381989cb000010f38b157000000001 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> content-type: application/json; charset=utf-8 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> date: Sat, 03 Apr 2021 06:51:43 GMT [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> etag: W/"53-hfEnumeNh6YirfjyjaujcOPPT+s" [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> expires: -1 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> nel: {"max_age":604800,"report_to":"cf-nel"} [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> pragma: no-cache [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> report-to: {"group":"cf-nel","endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=39vBUwnOjgmuV0yQJPiunD1hXHE28ku4%2FDq55GSjP%2B66ufTXnkgV1a%2F2H7DHSc28QRc1OiJA6k%2BKKXceS0z%2BaAFzxTU%2FuDpZCeBrgceQ7gvyxUQ45qbyYIa4sg2x"}],"max_age":604800} [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> server: cloudflare [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> set-cookie: __cfduid=dbe3ed123d14f8db7af7d7697a9f4049f1617432703; expires=Mon, 03-May-21 06:51:43 GMT; path=/; domain=.typicode.com; HttpOnly; SameSite=Lax [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> vary: Origin, Accept-Encoding [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> via: 1.1 vegur [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> x-content-type-options: nosniff [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> x-powered-by: Express [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> x-ratelimit-limit: 1000 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> x-ratelimit-remaining: 999 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: -> x-ratelimit-reset: 1616387857 [trace_id=48b49e15-f7c4-4991-9e33-23850a218718]
INFO: BODY Content-Type: application/json; charset=utf-8
INFO: BODY START
INFO: {
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
INFO: BODY END
Bearer Auth: refreshTokens callback blocks indefinitely when server returns 401
I am using ktor client v2.0.0-beta1,
I call the API that I called '/me' with the invalid token, then refresh token API as I excepted is called, and it failed because of our server logic,
my expected behavior is to get the error on my first API('/me') because refreshtoken API is failed. but nothing has happened. even I haven't got the exception anywhere.
ContentEncoding: "Unexpected EOF: expected 10 more bytes" when trying to decode HEAD response
If a web server responds to HEAD
request with Content-encode: gzip
header, ktor client fails with the following exception:
Unexpected exception occurred during switching: kotlinx.coroutines.channels.ClosedReceiveChannelException: Unexpected EOF: expected 10 more bytes
at io.ktor.utils.io.ByteBufferChannel.readFullySuspend(ByteBufferChannel.kt:594)
at io.ktor.utils.io.ByteBufferChannel.readFully(ByteBufferChannel.kt:586)
at io.ktor.utils.io.ByteBufferChannel.readPacketSuspend(ByteBufferChannel.kt:802)
at io.ktor.utils.io.ByteBufferChannel.readPacket$suspendImpl(ByteBufferChannel.kt:788)
at io.ktor.utils.io.ByteBufferChannel.readPacket(ByteBufferChannel.kt)
at io.ktor.utils.io.ByteReadChannelKt.readPacket(ByteReadChannel.kt:207)
at io.ktor.util.EncodersJvmKt$inflate$1.invokeSuspend(EncodersJvm.kt:68)
at io.ktor.util.EncodersJvmKt$inflate$1.invoke(EncodersJvm.kt)
at io.ktor.util.EncodersJvmKt$inflate$1.invoke(EncodersJvm.kt)
at io.ktor.utils.io.CoroutinesKt$launchChannel$job$1.invokeSuspend(Coroutines.kt:132)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Memory leak in ktor-client-curl
Receiving byte array data by GET request with using ktor-client-curl on native (macosX64) seems to be leaking memory, here's the snippet used to reproduce:
repeat(1000) {
runBlocking {
client.get("http://some-test-image.jpg")
val responseBody: ByteArray = httpResponse.receive()
}
}
Running that code shows constantly increasing memory usage of the process - using quite big images seems to be quickest way to observe it. This seems to be reproducible with 1.5.3, 1.6.0, 1.6.7 as well as with 2.0.0-beta-1 (with introduced API changes into snippet). I actually cherry-picked these versions amongst others and each seems to be affected.
Is there anything I'm assuming wrong here? I would expect heap size to stabilise around some usage instead.
Android: SocketException: Software caused connection abort - for every consecutive call after it failed in the streaming once
I have java.net.SocketException: Software caused connection abort
on Android in a following scenario:
- Start streaming with
client.get<HttpStatement>(url).execute {
. - Disable Internet on device - this breaks the streaming.
- This exception appears (which is expected at this point).
- Enable Internet back.
- Any consecutive call with the same HttpClient also throws this exception immediately.
The only solution to this I found so far is creating a new HttpClient for every call.
Might be related to: https://youtrack.jetbrains.com/issue/KTOR-870
The whole snippet that causes it:
var hashingSink: HashingSink? = null
var writeSink: BufferedSink? = null
try {
hashingSink = HashingSink.md5(destinationFile.sink())
writeSink = hashingSink.buffer()
httpClient.get<HttpStatement>(url = Url(urlPath)).execute { response: HttpResponse ->
var offset = 0
val channel = response.receive<ByteReadChannel>()
val contentLen = response.contentLength()?.toInt() ?: 0
val byteBufferSize = 1024 * 100
val buffer = ByteArray(byteBufferSize)
do {
val currentRead = channel.readAvailable(buffer, 0, byteBufferSize)
if (currentRead <= 0) break
writeSink.write(buffer, 0, currentRead)
val progress = if (contentLen == 0) 0 else (offset / contentLen.toFloat()) * 100
emit(progress)
offset += currentRead
} while (!channel.isClosedForRead)
writeSink.close()
}
val downloadChecksum = hashingSink.hash.hex()
if (downloadChecksum != checksum) throw ChecksumException(downloadChecksum, checksum)
} finally {
writeSink?.close()
hashingSink?.close()
}
So if I disable Internet on the device and get SocketException, the httpClient becomes unusable - every request I try to make ends up throwing the same exception.
Timeout in receiving streaming body breaks client
Setting DefaultRequest.url.protocol on the client side breaks the ability to establish a ws connection
Hello, guys! It seems setting defaultRequest.url.protocol
on the client side breaks the ability to establish a ws connection. Please, check it out.
If I set defaultRequest.url.protocol
, the client tries to establish a ws connection via http GET and fails.
But if I just comment off that setting, everything works.
multipart/form-data requests: No way of streaming data asynchronously
Right now the FormBuilder
and MultiPartFormDataContent
support only one streaming primitive Input
that is synchronous. This prevents streaming data in environments like JS because it's not viable to block the only thread for reading.
The suggested solution is to implement reading from the ByteReadChannel
.
Content-type header is removed from request when ContentNegotiation is used
The following test fails using 2.0.0-beta-1 because the content-type header is removed from the request:
@Test
fun contentTypeTest() {
val mockEngine = MockEngine { request ->
if (request.headers.contains(HttpHeaders.ContentType)) respondOk() else fail("Expected content type header")
}
val client = HttpClient(mockEngine) {
install(ContentNegotiation) {
jackson { }
}
}
runBlocking {
client.put("https://example.com/foo") {
contentType(ContentType.Application.Json)
setBody(mapOf("foo" to "bar"))
}
}
}
The content-type should not be removed (or changed when explicitly set in the request)
Kotlin/Native macOS target test build failed with an exception, exit code 139
IntelliJ IDEA 2021.3.1
Kotlin 1.6.10
Gradle 7.1
macOS 12.1 (21C52)
Xcode 13.2.1 Build version 13C100
* What went wrong:
Execution failed for task ':project:nativeTest'.
> command 'projectDir/build/bin/native/debugTest/test.kexe' exited with errors (exit code: 139)
gradle snippets
val commonMain by getting {
dependencies {
// Kotlinx Libraries
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.3.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-native-mt")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1")
implementation("org.jetbrains.kotlinx:atomicfu:0.17.0")
// Ktor
implementation("io.ktor:ktor-client-core:1.6.7")
implementation("io.ktor:ktor-client-serialization:1.6.7")
implementation("io.ktor:ktor-client-websockets:1.6.7")
implementation("io.ktor:ktor-client-encoding:1.6.7")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val jvmMain by getting {
dependencies {
implementation("io.ktor:ktor-client-cio:1.6.7")
}
}
val jvmTest by getting
val nativeMain by getting {
dependencies {
implementation("io.ktor:ktor-client-curl:1.6.7")
}
}
val nativeTest by getting
JS client seem to ignore `HttpCookies` feature (or header more generally) in browser target, but not in nodejs one
My Ktor JS client is not receiving proper headers in browser target, despite it being working in nodejs target.
I reproduced the issue using a simple Ktor server:
data class UserSession(val id: String, val count: Int)
fun main() {
embeddedServer(Jetty, port = 9000, host = "0.0.0.0") {
install(CORS) {
anyHost()
}
install(Sessions) {
cookie<UserSession>("user_session")
}
routing {
post("/login") {
val name = call.receive(String::class)
call.sessions.set(UserSession(id = name, count = 0))
call.respond(HttpStatusCode.NoContent)
}
get("/session") {
val userSession = call.sessions.get<UserSession>() ?: error("no session")
call.respond(userSession.id)
}
}
}.start(wait = true)
}
On the client side, my client build.gradle.kts
looks like:
kotlin {
jvm()
js(IR) {
browser()
nodejs()
}
// ...
}
Consider this test:
@Test
fun shouldLogin() = runTest {
val client = HttpClient(Js) {
install(HttpCookies)
install(Logging)
}
val name = "test"
client.post<String>("http://0.0.0.0:9000/login") { body = name }
val username = client.get<String>("http://0.0.0.0:9000/session")
assertEquals(name, username)
}
I observed the following:
Target | Test passing? |
---|---|
NodeJS | Yes |
Browser/ChromeHeadless96.0.4664.110,MacOS10.15.7 | No |
Browser/Firefox95.0,MacOS10.15 | No |
Logs from "js, node" test run:
HttpClient: REQUEST: http://0.0.0.0:9000/login
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 4
HttpClient: -> Content-Type: text/plain; charset=UTF-8
HttpClient: RESPONSE: 204 No Content
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: FROM: http://0.0.0.0:9000/login
HttpClient: COMMON HEADERS
HttpClient: -> connection: close
HttpClient: -> set-cookie: user_session=count%3D%2523i0%26id%3D%2523stest; Max-Age=604800; Expires=Sun, 09 Jan 2022 10:38:42 GMT; Path=/; HttpOnly; $x-enc=URI_ENCODING
HttpClient: REQUEST: http://0.0.0.0:9000/session
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: -> Cookie: user_session=count%3D%2523i0%26id%3D%2523stest
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 0
HttpClient: RESPONSE: 200 OK
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: FROM: http://0.0.0.0:9000/session
HttpClient: COMMON HEADERS
HttpClient: -> connection: close
HttpClient: -> content-length: 4
HttpClient: -> content-type: text/plain;charset=utf-8
HttpClient: -> set-cookie: user_session=count%3D%2523i0%26id%3D%2523stest; Max-Age=604800; Expires=Sun, 09 Jan 2022 10:38:42 GMT; Path=/; HttpOnly; $x-enc=URI_ENCODING
Logs from "js, browser, ChromeHeadless96.0.4664.110,MacOS10.15.7" test run:
HttpClient: REQUEST: http://127.0.0.1:9000/login
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 4
HttpClient: -> Content-Type: text/plain; charset=UTF-8
HttpClient: RESPONSE: 204 No Content
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: FROM: http://127.0.0.1:9000/login
HttpClient: COMMON HEADERS
HttpClient: REQUEST: http://127.0.0.1:9000/session
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 0
HttpClient: RESPONSE: 401 Unauthorized
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: FROM: http://127.0.0.1:9000/session
HttpClient: COMMON HEADERS
HttpClient: -> content-length: 0
It looks like common headers are absent, especially the crucial cookie related ones.
I do not know if it is a bug, or if I misconfigured something, any idea?
EDIT: I changed the issue from Multiplatform, to JS only as this is reproducible even using only the JS engine in two different targets.
Requesting with full url doesn't override defautlRequest url
I'm setting defaultRequest like this on my client factory:
defaultRequest {
url {
protocol = URLProtocol.HTTPS
host = "myapi.com"
encodedPath = "apiPath$encodedPath"
}
}
And I have an endpoint which sends request to a different host like this
suspend fun HttpClient.getOther(): Other = get("https://example.com/other")
I expect ktor to send request to https://example.com/other
I've tried to use different methods like:
suspend fun HttpClient.getOther(): Other = get {
url {
host = "example.com"
path("other")
}
}
suspend fun HttpClient.getOther(): Other = get {
host = "example.com"
url {
path("other")
}
}
All of them sent the request to https://myapi.com/apiPath/other
instead
Uncatchable `Software caused connection abort` on WSS
During a websocket connection when user turn off wifi connection he got "Software caused connection abort" exception. This exception is uncatchable so it cause application crash. When an unencrypted connection is used, exception is handled just as we expect.
Android api 30
Ktor: 1.6.7
Unchachable exception when use WSS
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-2
java.net.SocketException: Software caused connection abort
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:119)
at java.net.SocketInputStream.read(SocketInputStream.java:176)
at java.net.SocketInputStream.read(SocketInputStream.java:144)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788)
at okio.InputStreamSource.read(JvmOkio.kt:93)
at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:125)
at okio.RealBufferedSource.request(RealBufferedSource.kt:206)
at okio.RealBufferedSource.require(RealBufferedSource.kt:199)
at okio.RealBufferedSource.readByte(RealBufferedSource.kt:209)
at okhttp3.internal.ws.WebSocketReader.readHeader(WebSocketReader.kt:119)
at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.kt:102)
at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.kt:293)
at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:195)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
The same catched exception, but when using WS (unsecure protocol)
java.net.SocketException: Software caused connection abort
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:119)
at java.net.SocketInputStream.read(SocketInputStream.java:176)
at java.net.SocketInputStream.read(SocketInputStream.java:144)
at okio.InputStreamSource.read(JvmOkio.kt:93)
at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:125)
at okio.RealBufferedSource.request(RealBufferedSource.kt:206)
at okio.RealBufferedSource.require(RealBufferedSource.kt:199)
at okio.RealBufferedSource.readByte(RealBufferedSource.kt:209)
at okhttp3.internal.ws.WebSocketReader.readHeader(WebSocketReader.kt:119)
at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.kt:102)
at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.kt:293)
at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:195)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Maybe related to:
Core
Binary incompatibility 1.6.7 and 2.0.0-beta-1: NoSuchMethodError io.ktor.utils.io.bits.Memory.copyTo-iAfECsU
This may be expected behavior given the major version bump but wanted to document it and ask for guidance.
We have a dependency on ktor-io
in the AWS SDK for Kotlin and are getting reports that having ktor-server-*:2.0.0-beta1
in the dependency set results in runtime errors:
Exception in thread "main" java.lang.NoSuchMethodError: 'void io.ktor.utils.io.bits.Memory.copyTo-iAfECsU(java.nio.ByteBuffer, java.nio.ByteBuffer, long, long, long)'
Gradle is resolving the SDK dependency to latest version (+--- io.ktor:ktor-io:1.6.3 -> 2.0.0-beta-1
) and this is causing runtime issues. You can find the original issue here.
A dump of the class files shows the method renamed:
# 2.0.0-beta1
> javap Memory
Warning: File ./Memory.class does not contain class Memory
Compiled from "MemoryJvm.kt"
public final class io.ktor.utils.io.bits.Memory {
public static final io.ktor.utils.io.bits.Memory$Companion Companion;
public final java.nio.ByteBuffer getBuffer();
public static final long getSize-impl(java.nio.ByteBuffer);
public static final int getSize32-impl(java.nio.ByteBuffer);
public static final byte loadAt-impl(java.nio.ByteBuffer, int);
public static final byte loadAt-impl(java.nio.ByteBuffer, long);
public static final void storeAt-impl(java.nio.ByteBuffer, int, byte);
public static final void storeAt-impl(java.nio.ByteBuffer, long, byte);
public static final java.nio.ByteBuffer slice-87lwejk(java.nio.ByteBuffer, int, int);
public static final java.nio.ByteBuffer slice-87lwejk(java.nio.ByteBuffer, long, long);
public static final void copyTo-JT6ljtQ(java.nio.ByteBuffer, java.nio.ByteBuffer, int, int, int);
public static final void copyTo-JT6ljtQ(java.nio.ByteBuffer, java.nio.ByteBuffer, long, long, long);
public static java.lang.String toString-impl(java.nio.ByteBuffer);
public java.lang.String toString();
public static int hashCode-impl(java.nio.ByteBuffer);
public int hashCode();
public static boolean equals-impl(java.nio.ByteBuffer, java.lang.Object);
public boolean equals(java.lang.Object);
public static java.nio.ByteBuffer constructor-impl(java.nio.ByteBuffer);
public static final io.ktor.utils.io.bits.Memory box-impl(java.nio.ByteBuffer);
public final java.nio.ByteBuffer unbox-impl();
public static final boolean equals-impl0(java.nio.ByteBuffer, java.nio.ByteBuffer);
public static final java.nio.ByteBuffer access$getEmpty$cp();
static {};
}
# 1.6.7
> javap Memory
Warning: File ./Memory.class does not contain class Memory
Compiled from "MemoryJvm.kt"
public final class io.ktor.utils.io.bits.Memory {
public static final io.ktor.utils.io.bits.Memory$Companion Companion;
public final java.nio.ByteBuffer getBuffer();
public static final long getSize-impl(java.nio.ByteBuffer);
public static final int getSize32-impl(java.nio.ByteBuffer);
public static final byte loadAt-impl(java.nio.ByteBuffer, int);
public static final byte loadAt-impl(java.nio.ByteBuffer, long);
public static final void storeAt-impl(java.nio.ByteBuffer, int, byte);
public static final void storeAt-impl(java.nio.ByteBuffer, long, byte);
public static final java.nio.ByteBuffer slice-SK3TCg8(java.nio.ByteBuffer, int, int);
public static final java.nio.ByteBuffer slice-SK3TCg8(java.nio.ByteBuffer, long, long);
public static final void copyTo-f5Ywojk(java.nio.ByteBuffer, java.nio.ByteBuffer, int, int, int);
public static final void copyTo-iAfECsU(java.nio.ByteBuffer, java.nio.ByteBuffer, long, long, long);
public static java.lang.String toString-impl(java.nio.ByteBuffer);
public java.lang.String toString();
public static int hashCode-impl(java.nio.ByteBuffer);
public int hashCode();
public static boolean equals-impl(java.nio.ByteBuffer, java.lang.Object);
public boolean equals(java.lang.Object);
public static java.nio.ByteBuffer constructor-impl(java.nio.ByteBuffer);
public static final io.ktor.utils.io.bits.Memory box-impl(java.nio.ByteBuffer);
public final java.nio.ByteBuffer unbox-impl();
public static final boolean equals-impl0(java.nio.ByteBuffer, java.nio.ByteBuffer);
public static final java.nio.ByteBuffer access$getEmpty$cp();
static {};
}
I thought maybe the inline value class usage and compiler version may be the culprit. I tried upgrading our library to compile with Kotlin 1.6.10 and recompiling and seem to see the same issue though. Is there any workaround here that doesn't involve upgrading to ktor-2.x? We will likely eventually upgrade but my concern is this will bifurcate users of our library such that it works only if you are on the same ktor version as the library.
Module "io.ktor:ktor-network (io.ktor:ktor-network-iosarm64)" has a reference to symbol kotlinx.coroutines/SingleThreadDispatcher|null[0]
Using the new memory model with versions:
kotlinVersion=1.6.0
coroutinesVersion=1.5.1-new-mm-dev2
ktorVersion=1.6.2-native-mm-eap-196
Produces the following error when referencing ktor-network:
Module "io.ktor:ktor-network (io.ktor:ktor-network-iosarm64)" has a reference to symbol kotlinx.coroutines/SingleThreadDispatcher|null[0]. Neither the module itself nor its dependencies contain such declaration.
This could happen if the required dependency is missing in the project. Or if there is a dependency of "io.ktor:ktor-network (io.ktor:ktor-network-iosarm64)" that has a different version in the project than the version that "io.ktor:ktor-network (io.ktor:ktor-network-iosarm64): 1.6.2-native-mm-eap-196" was initially compiled with. Please check that the project configuration is correct and has consistent versions of all required dependencies.The list of "io.ktor:ktor-network (io.ktor:ktor-network-iosarm64): 1.6.2-native-mm-eap-196" dependencies that may lead to conflicts:
1. "io.ktor:ktor-io (io.ktor:ktor-io-iosarm64): 1.6.2-native-mm-eap-196" (was initially compiled with "io.ktor:ktor-io (io.ktor:ktor-io-iosarm64)")
2. "stdlib: 1.6.0" (was initially compiled with "stdlib: 1.5.30-RC")
3. "org.jetbrains.kotlin.native.platform.CoreFoundation: 1.6.0" (was initially compiled with "org.jetbrains.kotlin.native.platform.CoreFoundation: 1.5.30-RC")
4. "org.jetbrains.kotlin.native.platform.darwin: 1.6.0" (was initially compiled with "org.jetbrains.kotlin.native.platform.darwin: 1.5.30-RC")
5. "org.jetbrains.kotlin.native.platform.iconv: 1.6.0" (was initially compiled with "org.jetbrains.kotlin.native.platform.iconv: 1.5.30-RC")
6. "org.jetbrains.kotlin.native.platform.posix: 1.6.0" (was initially compiled with "org.jetbrains.kotlin.native.platform.posix: 1.5.30-RC")
7. "org.jetbrains.kotlinx:atomicfu (org.jetbrains.kotlinx:atomicfu-iosarm64): 0.17.0" (was initially compiled with "org.jetbrains.kotlinx:atomicfu (org.jetbrains.kotlinx:atomicfu-iosarm64): 0.16.1")
8. "org.jetbrains.kotlinx:kotlinx-coroutines-core (org.jetbrains.kotlinx:kotlinx-coroutines-core-iosarm64): 1.5.1-new-mm-dev2" (was initially compiled with "org.jetbrains.kotlinx:kotlinx-coroutines-core (org.jetbrains.kotlinx:kotlinx-coroutines-core-iosarm64): 1.5.1-new-mm-dev1")
IllegalStateException when writing in coroutine context backed by more than one thread
Expected results:
Successfully able to write to ByteWriteChannel regardless of coroutine context dispatched in
Actual results:
When the coroutine context write is called in is backed by more than 1 thread (e.g. Dispatchers.IO) after a few writes this exception get's thrown.
Exception in thread "DefaultDispatcher-worker-1" java.lang.IllegalStateException: Writing is not available in state Writing
at io.ktor.utils.io.internal.ReadWriteBufferState.startWriting$ktor_io(ReadWriteBufferState.kt:20)
at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:263)
at io.ktor.utils.io.ByteBufferChannel.writeInt$suspendImpl(ByteBufferChannel.kt:2972)
at io.ktor.utils.io.ByteBufferChannel.writeInt(ByteBufferChannel.kt)
at EchoServer$process$1$1.invokeSuspend(EchoServer.kt:38)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
MRE project attached, changing the number of threads in newFixedThreadPoolContext
stops the error from happening, alternatively changing the delay from 500 to 100ms
Looks like a concurrency issue, it might be the expected behaviour however it's not documented anywhere I found/the error message isn't very descriptive, and it would also break in the default example in the docs
Related to https://youtrack.jetbrains.com/issue/KTOR-710 which is apparently not a kotlin-io bug https://github.com/Kotlin/kotlinx-io/issues/43
Possible duplicate of https://youtrack.jetbrains.com/issue/KTOR-3025
Drop @ExperimentalTime
It is stable with Kotlin 1.6.0
Backport Client Certificate Authentication fix to Ktor v1.x
Please backport the fix for KTOR-1824 "Client Certificate Authentication" to Ktor v1.x.
It is the only thing preventing my team from considering the use of Ktor in our new server applications.
Thank you.
ByteReadPacket.headerSizeHint is unused
May be it's a good time to remove headerSizeHint
in 2.0, as it not used at all?
Coroutines update
Newer versions of coroutines don't seem to have the SingleThreadDispatcher class which is used by ktor.
Updating coroutines to 1.6.0 breaks the build, see the following error
Module "io.ktor:ktor-network (io.ktor:ktor-network-iosx64)" has a reference to symbol kotlinx.coroutines/SingleThreadDispatcher|null[0]. Neither the module itself nor its dependencies contain such declaration.
This could happen if the required dependency is missing in the project. Or if there is a dependency of "io.ktor:ktor-network (io.ktor:ktor-network-iosx64)" that has a different version in the project than the version that "io.ktor:ktor-network (io.ktor:ktor-network-iosx64): 1.6.6" was initially compiled with. Please check that the project configuration is correct and has consistent versions of all required dependencies.
The list of "io.ktor:ktor-network (io.ktor:ktor-network-iosx64): 1.6.6" dependencies that may lead to conflicts:
1. "io.ktor:ktor-io (io.ktor:ktor-io-iosx64): 1.6.6" (was initially compiled with "io.ktor:ktor-io (io.ktor:ktor-io-iosx64)")
2. "org.jetbrains.kotlinx:kotlinx-coroutines-core (org.jetbrains.kotlinx:kotlinx-coroutines-core-iosx64): 1.6.0" (was initially compiled with "org.jetbrains.kotlinx:kotlinx-coroutines-core (org.jetbrains.kotlinx:kotlinx-coroutines-core-iosx64): 1.5.2-native-mt")
Compression slow due to using BEST_COMPRESSION for deflate/gzip
Ktor currently uses BEST_COMPRESSION for java.util.zip.Deflater
when the feature Compression
is enabled. It should use DEFAULT_COMPRESSION rather than BEST_COMPRESSION.
BEST_COMPRESSION is generally many times slower than DEFAULT_COMPRESSION for miniscule improvements to compressed size, making BEST_COMPRESSION almost always the wrong choice when compression time is part of the equation.
Fixing this would probably also partially fix KTOR-1341 (compression is still expensive, but significantly less so).
Ideally compression level should be configurable, since the optimal choice depends on expected network speed, CPU speed, and which implementation the JDK uses, but DEFAULT_COMPRESSION is a pretty good default.
Ktor pollutes the completion list with internal functions: `Any.preventFreeze()` and `Any.makeShared()`
For me every completion list for every member access contains preventFreeze()
and makeShared
only because one of my dependencies (not me) uses ktor. I ofter use a completion list for observing members and seeing these two function every time is quite annoying. I personally think that having such extension functions on primitive type is a pretty bad practice since it pollutes everyone. If you have such dangerous API that shouldn't be normally used, probably it's better to define them as global functions without receiver.
To be honest, I would be very interested to know the reasoning behind the decision about making such functions, since if every kotlin library would add two extension functions to Any it would be probably nightmare. Also I'm wondering is any chance that these two functions would be removed from the completion list of every member access in future updates?
Incompatible change from io.ktor:ktor-server-core:1.6.5 to 1.6.6
Hi Team!
Within your class: io.ktor.http.URLBuilder.kt you changed the signiture of Url from
public data class Url
To
public data class Url internal constructor
Which prevents the usage for us. We are using it like:
private fun sanitize(url: Url): Url {
return Url(
protocol = url.protocol,
host = url.host,
specifiedPort = url.specifiedPort,
encodedPath = url.encodedPath,
parameters = sanitizeParameters(url.parameters),
fragment = url.fragment,
user = url.user,
password = url.password,
trailingQuery = url.trailingQuery,
)
}
Can you provide a fixed version e.g. 1.6.7 ? This would be the best for all customers of your library.
or provide a fix. I guess it should work somehow with the URLBuilder, but the new ParameterBuilder makes the compiler unhappy.
Docs
Documentation about how to configure libcurl on Windows
There should be a documentation about how to configure libcurl on Windows using minGW and Cygwin to be able to use ktor-client-curl
engine.
The issue KTOR-3989 if resolved should be documented too.
Also, some information about troubleshooting common problems would be helpful.
Update the 'Manual Configuration' help link after the 2.0.0 release
Provide an example how to use new MultiPartFormDataContent (#KTOR-325)
Recently PR for #KTOR-325 has been pushed, and I'd like to have a test or an example in documentation how to use this new API as changing the contentType is what I'd like to have in my project (currently in my version (I had to copy the whole file into my project) it receives baseContentType
with a restriction to match ContentType.MultipartAny
without any parameters.
Client docs for desktop are misleading
As evident from this slack thread, ktor-client docs for native desktop platforms are misleading. The docs should be explicit that they are referring only to desktop apps built with kotlin native. Additionally, it might also be worthwhile to review the language for jvm platform to indicate that client engines there can be used for jvm desktop apps as well, not just servers.
This also leads to false-positive issues like KTOR-3794
In docs and generated Gradle, Prometheus is misspelled as Promteteus
This might seem a bit of a petty issue to raise, but I've noticed that in the documentation, code snippets, and Gradle generated files, Prometheus is misspelled as Prometeus.
implementation("io.micrometer:micrometer-registry-prometheus:$prometeus_version")
Despite it being spelled as "prometheus" right next to it.
Annoying, but really annoying for some people.
Again, I appreciate it's a little petty, but help a guy with OCD out? :)
Include changes from hands-on PR: Update 03_customer-routes.md #120
(Changes proposed initially in the kotlin-hands-on repository, since the tutorial is now moved to https://ktor.io/docs/creating-http-apis.html, linking it here):
The section about how to create a mutable list and where it should be in the code was a little bit confusing
Changing the return HttpStatusCode of Post route to store customer. In that this, case it's more common to use 201 (Created) instead of 202 (Accepted)
Update URL for the 'Adding Ktor dependencies' topic and add redirects
Insecure user session samples in documentation
Right now documentation samples (here and here) don't mention authentication and encryption configuration of sessions which may result in insecure implementation if user doesn't already know importance of it and won't configure it on their own.
Unsigned/unencrlypted sessions are very insecure and some users may not be aware of it.
Also documentation and samples should not provide a sample of a key, and if a sample given then it should be blacklisted, so users won't be able to copy paste code snippet from documentation and reuse it, making the implementation insecure.
Generator
Implement frontend for redesigned Ktor Project Generator
Current frontend: http://start.ktor.io/
New Design: https://zpl.io/V0XkGkK
Current frontend repo: github.com/ktorio/ktor-plugin
Localization: no
Current questions:
- [x] Put together gatsbyjs based project to start working on generator
- [x] Make a decision whether develop generator as separate project (create a new repo in this case) or as a separate component and put them to Ktor landing
- [x] Discuss UX pitfalls such as ability to move between wizard steps, page with markdown layout, how to edit selected feature list.
- [ ] Do we need a dark theme? It needs to add that states to the design.
- [ ] Do we need a mobile version? (probably not, so we need a disclaimer in this case) How it should look like on a wide screen?
- [x] Margins and components are not consistent with webteam UI, is it ok to use webteam UI design system?
Current development tasks:
- [x] Fix saving staff to local storage (@pshenichniy.eugene)
- [x] API and react-actions refactoring (@Ekaterina_Zaikina)
- [x] Artifact control (@pshenichniy.eugene, @Ekaterina_Zaikina)
- [x] "Configuration in" control (@pshenichniy.eugene)
- [x] "Add sample code” control (@pshenichniy.eugene)
- [x] Simple third tab with link to Download, if not yet (@Ekaterina_Zaikina)
- [x] Fix the rest of warnings in console (@Ekaterina_Zaikina)
- [ ] Fix tests for redux store
- [x] Prettify loader for loading documentation for the selected plugin (@Ekaterina_Zaikina)
- [x] Apply comments after design review to the first step (@Ekaterina_Zaikina)
- [x] Apply comments after design review to the second step (@Ekaterina_Zaikina)
- [x] Create task for wording review and ask someone to review (@Ekaterina_Zaikina)
- [x] Design review of the third tab (@Ekaterina_Zaikina)
- [x] Add shortcuts navigation to the list of plugins (@Ekaterina_Zaikina)
- [x] Add google or/and FUS analytics
- [x] Improve header layout for narrow screens
Support macOs M1 in CLI generator
Generator performance: cache Maven requests
We are getting more users and generator gets higher RPS rate which leads to memory usage growth.
We need to consider caching all internal requests to fit into our memory limits.
Migrations of the client code are not working for queries with non-trivial expression body
Migrations are unavailable
https://ktor-plugin.europe-north1-gke.intellij.net/migrations -- returns 500
From IDE it looks like after clicking migrate
button, nothing happens and a failure message appears with a Try again
button
Infrastructure
Publish Javadoc as a maven artifact
Currently, the javadoc/dokka output is not published as a maven artifact.
The javadoc jar published to maven central looks like this:
ktor-server-core-1.6.7-javadoc/
└── META-INF
└── MANIFEST.MF
1 directory, 1 file
It would be great it you could publish the output of dokka to maven, rather than just to the api.ktor.io site.
Infrastructure: Build with JDK 11 for all modules fails: Can't inline metric micrometer because it uses jvm target 8
Kotlin 1.6.0 uses JVM target 8 by default, and Ktor dropped support for JVM target 6 and 7. If you want to use JDK 11 for all! modules, the Kotlin compiler cannot inline jvm 8 target binary code into jvm 11 byte code.
So there is no need to define JVM target 8 explicit in 1 module.
=> Remove JVM target 8 in metrics micrometer
Apple Arm: 'Resolving NPM dependencies using yarn' returns 139
If you want to build Ktor (main branch) on an Apple Arm, the build exits with: Resolving NPM dependencies using yarn' returns 139
.
I don't know the exact reason, but it is resolved with the latest nodeJS version: 16.13.1.
Simple reproducer is attached.
nodeYarn.zip
IntelliJ IDEA Plugin
Generator performance: make requests from IDE only if user clicks something. Otherwise -- show static (maybe outdated) page
We are getting more users and generator gets higher RPS rate which leads to memory usage growth.
Most of the requests are first-page requests from IDE (as logs show)
We need to consider limiting requests from IDE via hardcoding first page content and only make requests in background in case user really does something.
Ktor does not prompt to auto-install JsonFeature for clients
Created an empty project with Gradle and only added the following dependencies:
dependencies {
testImplementation(kotlin("test"))
implementation("io.ktor:ktor-client-core:1.6.7")
implementation("io.ktor:ktor-client-cio:1.6.7")
}
According to Hadi, this should give me autocomplete to add the feature and related dependency :)
New Project Wizard: Ktor generator is empty on first open (UPAE from KtorProjectSettingsStep)
-
Open 221 EAP Nightly
-
File -> New Project
-
Go to Ktor in Generators sidebar
-
Ktor tab is empty. Next button is available.
-
Click Next button. Exception is thrown, nothing happens
kotlin.UninitializedPropertyAccessException: lateinit property projectSettingsTemplate has not been initialized
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep$initialProjectName$2.invoke(KtorProjectSettingsStep.kt:43)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep$initialProjectName$2.invoke(KtorProjectSettingsStep.kt:42)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep.getInitialProjectName(KtorProjectSettingsStep.kt:42)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep.access$getInitialProjectName(KtorProjectSettingsStep.kt:33)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep$projectNameProperty$1.invoke(KtorProjectSettingsStep.kt:48)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep$projectNameProperty$1.invoke(KtorProjectSettingsStep.kt:47)
at com.intellij.openapi.observable.properties.AtomicLazyProperty$update$resolve$1.invoke(AtomicLazyProperty.kt:32)
at com.intellij.openapi.observable.properties.AtomicLazyProperty$update$1.apply(AtomicLazyProperty.kt:33)
at java.base/java.util.concurrent.atomic.AtomicReference.updateAndGet(AtomicReference.java:209)
at com.intellij.openapi.observable.properties.AtomicLazyProperty.update(AtomicLazyProperty.kt:33)
at com.intellij.openapi.observable.properties.AtomicLazyProperty.get(AtomicLazyProperty.kt:16)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep.getLocation(KtorProjectSettingsStep.kt:239)
at io.ktor.initializr.intellij.settings.KtorProjectSettingsStep.validate(KtorProjectSettingsStep.kt:218)
at com.intellij.ide.projectWizard.ProjectTypeStep.validate(ProjectTypeStep.java:653)
at com.intellij.ide.util.newProjectWizard.AbstractProjectWizard.commitStepData(AbstractProjectWizard.java:236)
at com.intellij.ide.util.newProjectWizard.AbstractProjectWizard.doNextAction(AbstractProjectWizard.java:255)
at com.intellij.ide.wizard.AbstractWizard.proceedToNextStep(AbstractWizard.java:249)
at com.intellij.ide.wizard.AbstractWizard$5.actionPerformed(AbstractWizard.java:201)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:270)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6654)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3345)
at java.desktop/java.awt.Component.processEvent(Component.java:6419)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:885)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:814)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:737)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:433)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:802)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:432)
at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106)
at com.intellij.ide.IdeEventQueue.performActivity(IdeEventQueue.java:598)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8(IdeEventQueue.java:430)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:873)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:478)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117)
at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:190)
at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235)
at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233)
at java.desktop/java.awt.Dialog.show(Dialog.java:1070)
at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl$MyDialog.show(DialogWrapperPeerImpl.java:701)
at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl.show(DialogWrapperPeerImpl.java:438)
at com.intellij.openapi.ui.DialogWrapper.doShow(DialogWrapper.java:1672)
at com.intellij.openapi.ui.DialogWrapper.show(DialogWrapper.java:1630)
at com.intellij.openapi.ui.DialogWrapper.showAndGet(DialogWrapper.java:1644)
at com.intellij.ide.impl.NewProjectUtil.createNewProject(NewProjectUtil.java:75)
at com.intellij.ide.actions.NewProjectAction.actionPerformed(NewProjectAction.java:21)
at com.intellij.openapi.actionSystem.ex.ActionUtil.lambda$performActionDumbAwareWithCallbacks$4(ActionUtil.java:244)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:265)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks(ActionUtil.java:244)
at com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenActionsUtil.performAnActionForComponent(WelcomeScreenActionsUtil.java:96)
at com.intellij.openapi.wm.impl.welcomeScreen.WelcomeScreenActionsUtil$ToolbarTextButtonWrapper$1.actionPerformed(WelcomeScreenActionsUtil.java:56)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:270)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6654)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3345)
at java.desktop/java.awt.Component.processEvent(Component.java:6419)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:885)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:814)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:737)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:433)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:802)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:432)
at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:119)
at com.intellij.ide.IdeEventQueue.performActivity(IdeEventQueue.java:598)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8(IdeEventQueue.java:430)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:873)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:478)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
- Close wizard, go to step 2. Ktor tab is usually shown now
EA link for exception
https://ea.jetbrains.com/browser/ea_reports/9040613
Reproduced on
- IDEA: 2022.1 EAP nightly, #IU-221.4286, built on February 10, 2022
- Kotlin: 221-1.6.20-RC-138-IJ4286
Don't perform migrations for MPP projects
Migrations have known problems when it comes to MPP due to the lack of support of Kotlin MPP in IDE.
We must not show migration notification and/or perform migrations on MPP modules.
The main issue is that the current build tools API in IntelliJ (see DependencyModifierService) does not work properly with Kotlin MPP DSL in Gradle because this DSL is not supported.
If you run a migration for Ktor that tries to work with MPP dependencies in the same way as with a normal dependencies, it will just add a new outer block of dependencies { ... }
in your build script. Instead, it must be adding dependencies inside macOs64 { dependencies { ... } }
or other similar places for all relevant platforms
Migrate Generator to New Testing API
localization issue with new project wizard - plugin page
IU-221.4501.155, JRE 11.0.14+9-b1993.2x64 JetBrains s.r.o., OS Mac OS X(aarch64) v12.2.1, screens 5120.0x2880.0; Retina
Steps to reproduce the issue
- install language pack
- start IntelliJ IDEA
- create new Ktor project
- at plugin page, search "json"
- click "Add" for kotlinx.serialization
Expected
... プラグイン が追加されました
Actual:
... プラグインs が追加されました
Seems like "s" is added in a code for a message in English, to make "plugin" as "plugins"(plural), which is not appropriate for messages to be localized.
There were similar issues in IDE/bundled plugin and they were fixed already. Need a similar fix with Ktor (plugin?) as well.
{width=719px}
Ktor plugin is asking to migrate to EAP versions
Nightly 2022.1
Sort endpoints in Endpoint view and when creating tests
Currently, tests for endpoints may appear in any order in multi-test dialogs and in the created tests file itself. This is hardly testable and for larger projects the order of the tests might be a mess.
Instead of showing them in random order, we can sort them by URL/HTTP method and then they will look prettier and it will be easier to test them since the order is always the same and it does not depend on what we found first.
Performance: Don't store PSI elements in Ktor Url Mappings. Use Smart Reference or PSI Anchor, instead
Put label to local history before performing migration in Ktor
Migrations are project-wide operations and they may affect the state of the project making it not compilable. This is a dangerous operation and it's recommended to add a bookmark in local history so that one may roll back to the state right before the migration.
Could not resolve: io.ktor:ktor-locations:2.0.0-beta-1 on a new project created with IDEA 2021.3.1
Hello,
The default version when creating a ktor project with IDEA 2021.3.1 is 2.0.0-beta-1, but the last published version for ktor-locations is https://search.maven.org/artifact/io.ktor/ktor-locations/1.6.7/pom
This causes the first build to fail with the following error.
09:39:54: Executing ':classes'...
Starting Gradle Daemon...
Gradle Daemon started in 1 s 321 ms
> Task :compileKotlin FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileKotlin'.
> Error while evaluating property 'filteredArgumentsMap' of task ':compileKotlin'
> Could not resolve all files for configuration ':compileClasspath'.
> Could not find io.ktor:ktor-locations:2.0.0-beta-1.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-locations/2.0.0-beta-1/ktor-locations-2.0.0-beta-1.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-locations/2.0.0-beta-1/ktor-locations-2.0.0-beta-1.pom
Required by:
project :
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 14s
1 actionable task: 1 executed
09:40:12: Execution finished ':classes'.
Make migrations more configurable
Issues:
- Some people work on multi-module projects in mono repositories and they don't want to migrate the whole project (this will disturb other teams when changing irrelevant modules)
- We are always showing this notification once a new version arrives. There must be an option like "Don't show again"
- We are suggesting EAPs and Betas as well as stable releases. There must be an option to select migration version levels.
Ktor plugin in IDEA 2021.3 suggests migrating the 2.0.0-eap project to 1.6.6
- Run IDEA 2021.3.
- Open the https://github.com/ktorio/ktor-documentation/tree/main/codeSnippets project and switch to the 2.0.0 branch.
=> IDEA suggests migrating this project to 1.6.6.
P.S. Maybe it's related to absense of the 2.0.0-eap version in a plugin for IDEA 2021.3.
Server
Reified type causes ApplicationCall.receive() throw UOE: This function has a reified type parameter and thus can only be inlined at compilation time, not called directly.
The following code (Kotlin 1.6.10, Ktor 1.6.7, Java 17.0.1, jvmTarget = "1.8") reproduces the error:
@Serializable
data class Age(val value: Int)
@Serializable
data class Update<T>(val old: T, val new: T)
fun main() {
embeddedServer(Netty, port = 8080) {
install(ContentNegotiation) {
json()
}
routing {
update<Age>()
}
}.start(wait = true)
}
inline fun <reified T> Route.update() {
post("/") {
val update = call.receive<Update<T>>()
application.log.info("update=$update")
call.respond(HttpStatusCode.OK, "OK")
}
}
Sending the following request:
$ curl -v -H "Content-Type: application/json" -POST http://localhost:8080/ -d '{"old":{"value":1},"new":{"value":2}}'
makes server throw:
java.lang.UnsupportedOperationException: This function has a reified type parameter and thus can only be inlined at compilation time, not called directly.
at kotlin.jvm.internal.Intrinsics.throwUndefinedForReified(Intrinsics.java:207)
at kotlin.jvm.internal.Intrinsics.throwUndefinedForReified(Intrinsics.java:201)
at kotlin.jvm.internal.Intrinsics.reifiedOperationMarker(Intrinsics.java:211)
at ServerKt$update$1.invokeSuspend(server.kt:34)
at ServerKt$update$1.invoke(server.kt)
at ServerKt$update$1.invoke(server.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:78)
at io.ktor.routing.Routing.executeResult(Routing.kt:155)
at io.ktor.routing.Routing.interceptor(Routing.kt:39)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:107)
at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:145)
at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:78)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:127)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:78)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:123)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.startCoroutineImpl(Builders.common.kt:194)
at kotlinx.coroutines.BuildersKt.startCoroutineImpl(Unknown Source)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:134)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:43)
at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:34)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:370)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda-1$lambda-0(NettyApplicationEngine.kt:251)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:831)
I found similar problem KTOR-582 that was identified as Kotlin compiler’s issue and eventually resolved as Fixed.
Problem with websockets when deploying to a jetty server as a war
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/1032
Ktor Version
1.1.3
Ktor Engine Used(client or server and name)
Jetty
JVM Version, Operating System and Relevant Context
Ubuntu 18
Feedback
Hi.
I am having problems with websockets and jetty.
Everythings works fine when execute my app as stand-alone, but when i pack the app in a war, and deploy it to an external jetty i am having problems with websockets connection.
When i open a websockets conneciton i get the following exception:
21-Mar 08:10:55.349 ERROR - 101 Switching Protocols: GET - /api-sample/ws
java.lang.ClassCastException: org.eclipse.jetty.server.HttpConnection cannot be cast to org.eclipse.jetty.io.Connection
at io.ktor.server.jetty.internal.JettyUpgradeImpl$performUpgrade$2.invokeSuspend(JettyUpgradeImpl.kt:25)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
I have been inspecting the code, and the problem seems to be in this file:
In the line 25:
val connection = servletRequest.getAttribute(HttpConnection::class.qualifiedName) as Connection
Tries to do a cast that fails , because the connection is an HttpConnection.
It takes long time to stop server with Netty engine
it takes couple of seconds to stop running app via CTRL+C
StatusPages plugin executes wrong handler on exception
https://ktor.io/docs/status-pages.html#exceptions"Each call is only caught by a single exception handler, the closest exception on the object graph from the thrown exception. When multiple exceptions within the same object hierarchy are handled, only a single one will be executed."
Returning Thymeleaf fragments from Routes
In Spring Framework, its possible to return a Thymeleaf fragment. Is such feature also available in Ktor Thymeleaf Plugin?
Rewrite HSTS to new plugins API
Rewrite FreeMarker to new Plugins API
Rewrite ConditionalHeaders to New Plugins API
SinglePageApplication plugin returns 404 for non-existent paths
What steps will reproduce the issue?
Version: Ktor 2.0.0-eap-329
install(SinglePageApplication) {
useResources = true
filesPath = "static"
}
And put an index.html file under src/main/resources/static.
Try GET /a.
What is the expected result?
index.html should be served, as this is supposed to be used with SPAs.
What happens instead?
404.
The SPA plugin code is like this:
static(applicationRoute) {
if (usePackageNames) {
resources(filesPath)
defaultResource(defaultPage, filesPath)
} else { ... }
}
Where defaultResource is:
public fun Route.defaultResource(resource: String, resourcePackage: String? = null) {
val packageName = staticBasePackage.combinePackage(resourcePackage)
get {
val content = call.resolveResource(resource, packageName)
if (content != null) {
call.respond(content)
}
}
}
It uses get
, which only matches the root route and nothing else. If you do something like this, then it will give the behavior suitable for a SPA.
routing {
route("/") {
resources("static")
}
route("/*") {
defaultResource("index.html", "static")
}
}
The adequate test cases were completely missing, as the tests only checked for behavior on files that exists.
InvalidPathException in ApplicationEngineEnvironmentReloading
I am not sure what is to blame but URLs such as:
file:\C:\Users\spand\IdeaProjects\hltv\dust2\dust2-main\build\libs\dust2-main.jar!\dust2
can end up in the list of paths to watch in ApplicationEngineEnvironmentReloading. This fails as described below. Can we either ignore them or clean up these paths ? (both file:
prefix and the !\dust2
suffix seem irrelevant)
private fun watchUrls(urls: List<URL>) {
val paths = HashSet<Path>()
for (url in urls) {
val path = url.path ?: continue
val decodedPath = URLDecoder.decode(path, "utf-8")
val folder = File(decodedPath).toPath() <----
Exception in thread "main" java.nio.file.InvalidPathException: Illegal char <:> at index 4: file:\C:\Users\spand\IdeaProjects\hltv\dust2\dust2-main\build\libs\dust2-main.jar!\dust2
at java.base/sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
at java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:229)
at java.base/java.io.File.toPath(File.java:2310)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.watchUrls(ApplicationEngineEnvironmentReloading.kt:231)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createClassLoader(ApplicationEngineEnvironmentReloading.kt:193)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:137)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:277)
at io.ktor.server.jetty.JettyApplicationEngineBase.start(JettyApplicationEngineBase.kt:48)
at io.ktor.server.jetty.JettyApplicationEngine.start(JettyApplicationEngine.kt:23)
at io.ktor.server.jetty.JettyApplicationEngine.start(JettyApplicationEngine.kt:14)
at io.ktor.server.engine.ApplicationEngine$DefaultImpls.start$default(ApplicationEngine.kt:56)
[snipped]
Building native image fails (v2.0)
./build.sh
Warning: Option 'EnableAllSecurityServices' is deprecated and might be removed from future versions
========================================================================================================================
GraalVM Native Image: Generating 'graal-server'...
========================================================================================================================
[1/7] Initializing... (1.9s @ 0.22GB)
Version info: 'GraalVM 22.0.0.2 Java 17 CE'
1 user-provided feature(s)
- com.oracle.svm.polyglot.kotlin.KotlinFeature
[2/7] Performing analysis... [] (1.0s @ 0.57GB)
2,019 (72.08%) of 2,801 classes reachable
1,529 (47.38%) of 3,227 fields reachable
5,673 (63.21%) of 8,975 methods reachable
29 classes, 9 fields, and 50 methods registered for reflection
Fatal error: com.oracle.graal.pointsto.util.AnalysisError$ParsingError: Error encountered while parsing io.netty.bootstrap.ServerBootstrap.validate()
Parsing context:
at io.netty.bootstrap.ServerBootstrap.validate(ServerBootstrap.java:164)
at io.netty.bootstrap.ServerBootstrap.validate(ServerBootstrap.java:45)
at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:267)
at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:253)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:187)
at com.example.ApplicationKt.main(Application.kt:11)
at com.example.ApplicationKt.main(Application.kt)
at com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:141)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.createTypeFlow(MethodTypeFlow.java:315)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureTypeFlowCreated(MethodTypeFlow.java:286)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:107)
at com.oracle.graal.pointsto.DefaultAnalysisPolicy$DefaultVirtualInvokeTypeFlow.onObservedUpdate(DefaultAnalysisPolicy.java:223)
at com.oracle.graal.pointsto.flow.TypeFlow.notifyObservers(TypeFlow.java:487)
at com.oracle.graal.pointsto.flow.TypeFlow.update(TypeFlow.java:556)
at com.oracle.graal.pointsto.PointsToAnalysis$2.run(PointsToAnalysis.java:598)
at com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:195)
at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:179)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of ch.qos.logback.classic.Logger are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use --trace-object-instantiation=ch.qos.logback.classic.Logger.
at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.checkImageHeapInstance(ClassInitializationFeature.java:133)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.replaceObject(AnalysisUniverse.java:575)
at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.replaceObject(AnalysisConstantReflectionProvider.java:217)
at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.interceptValue(AnalysisConstantReflectionProvider.java:188)
at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.readValue(AnalysisConstantReflectionProvider.java:102)
at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.readFieldValue(AnalysisConstantReflectionProvider.java:81)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.util.ConstantFoldUtil$1.readValue(ConstantFoldUtil.java:51)
at jdk.internal.vm.compiler/org.graalvm.compiler.core.common.spi.JavaConstantFieldProvider.readConstantField(JavaConstantFieldProvider.java:84)
at com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider.readConstantField(AnalysisConstantFieldProvider.java:72)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.util.ConstantFoldUtil.tryConstantFold(ConstantFoldUtil.java:47)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.java.LoadFieldNode.asConstant(LoadFieldNode.java:166)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.java.LoadFieldNode.canonical(LoadFieldNode.java:132)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.java.LoadFieldNode.canonical(LoadFieldNode.java:123)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.java.LoadFieldNode.canonical(LoadFieldNode.java:68)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.spi.Canonicalizable$Unary.canonical(Canonicalizable.java:101)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.SimplifyingGraphDecoder.canonicalizeFixedNode(SimplifyingGraphDecoder.java:209)
at jdk.internal.vm.compiler/org.graalvm.compiler.replacements.PEGraphDecoder.canonicalizeFixedNode(PEGraphDecoder.java:1539)
at com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder.canonicalizeFixedNode(InlineBeforeAnalysis.java:194)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.SimplifyingGraphDecoder.handleFixedNode(SimplifyingGraphDecoder.java:188)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.GraphDecoder.processNextNode(GraphDecoder.java:792)
at com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder.processNextNode(InlineBeforeAnalysis.java:242)
at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.GraphDecoder.decode(GraphDecoder.java:529)
at jdk.internal.vm.compiler/org.graalvm.compiler.replacements.PEGraphDecoder.decode(PEGraphDecoder.java:822)
at com.oracle.graal.pointsto.phases.InlineBeforeAnalysis.decodeGraph(InlineBeforeAnalysis.java:99)
at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:175)
at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:358)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.createTypeFlow(MethodTypeFlow.java:297)
... 14 more
------------------------------------------------------------------------------------------------------------------------
0.1s (3.5% of total time) in 12 GCs | Peak RSS: 1.03GB | CPU load: 9.42
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
/graal-server.build_artifacts.txt
========================================================================================================================
Failed generating 'graal-server' after 3.0s.
Error: Image build request failed with exit status 1
---
val ktor_version: String by project
val kotlin_version: String by project
val logback_version: String by project
plugins {
application
kotlin("jvm") version "1.6.10"
id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10"
id("com.github.johnrengelman.shadow") version "7.0.0"
}
group = "com.example"
version = "0.0.1"
application {
mainClass.set("com.example.ApplicationKt")
val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
}
repositories {
mavenCentral()
maven { url = uri("https://maven.pkg.jetbrains.space/public/p/ktor/eap") }
}
tasks{
shadowJar {
manifest {
attributes(Pair("Main-Class", "com.example.ApplicationKt"))
}
}
}
dependencies {
implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version")
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}
CIO server https support
On current moment CIO server engine doesn't support HTTPS both on JVM and native
Prototype of JVM implementation using SSLEngine: https://github.com/ktorio/ktor/pull/2911
Ktor uses too much memory compared to other Http server libraries
Hi, Under the load scenario we are testing in my team lately, Ktor is using way more memory than other libraries, like Kooby(Jooby).
jdk1.8.0_221
After 500 seconds of stress tests of the same 4 endpoints, check the memory and CPU usage:
Jooby 2.13.0:
Ktor:
Ktor implementation code:
server:
embeddedServer(
Netty,
host = ip,
port = port,
module = Application::module,
configure = {
requestQueueLimit = 8
runningLimit = 5
shareWorkGroup = true
configureBootstrap = {
group(NioEventLoopGroup(8, Executors.newCachedThreadPool()))
}
}
).start(wait = true)
features:
install(DefaultHeaders)
install(ContentNegotiation) {
register(ContentType.Application.Json, JacksonConverter(JSON))
}
routes:
fun route(parentRoute: Route) {
parentRoute.invoke {
post("/games/{gameId}/validate") { call.respond(HttpStatusCode.MethodNotAllowed) }
post("/games/{gameId}/play") {
call.respond(HttpStatusCode.OK, "hola")
}
get("/games/{gameId}/config") {
call.respond(HttpStatusCode.OK, "hola")
}
post("/games/{gameId}/checksum") {
call.respond(HttpStatusCode.OK, "hola")
}
get("/games/{gameId}/version") {
call.respond(HttpStatusCode.OK, "hola")
}
get("/games/{gameId}/initialize") {
call.respond(HttpStatusCode.OK, "hola")
}
post("/games/{gameId}/evaluate/{objectiveId}") {
call.respond(HttpStatusCode.OK, "hola")
}
}
}
As you can see, the endopints are quite simple.
The test:
We used Gatling to stress the servers, this is the code:
Basically, 500 users per second peform 4 api calls.
Any further question, please let me know.
Add jte template support
Jte is a template engine similar to freemarker, you can read more about it here: jte.gg
I think it would make a great addition to the Ktor server plugins, as it directly compiles templates to .class files for fast view generation.
CBOR encoding increases response size rather than reducing.
Json string of 4MB becomes 12MB while encoding with CBOR. It should reduce size. Is there anything that can help me to reduce response size?
val bytes = Cbor.encodeToByteArray(jsonString)
Add support for list size methods in PlaceholderList
Hi! It would be nice to add this methods to PlaceholderList
:
isNotEmpty()
size
For example for cases like:
class TodoTemplate : Template<FlowContent> {
val item = PlaceholderList<UL, FlowContent>()
override fun FlowContent.apply() {
if (item.isNotEmpty()) {
p { +"Number of tasks: ${item.size}" }
ul {
each(item) {
li {
insert(it)
}
}
}
}
}
}
Missing headers in OutgoingContent
The headers
object in OutgoingContent
is empty even if headers has been set on the response.
Ktor error using AutoReload configuration with tcnative (http/2)
Hi,
I'm using ktor 1.6.5 with Netty TCNative 2.5.0. When I try to active the AutoReload configuration using the example from https://ktor.io/docs/auto-reload.html#enable
I got this error:
So, the ktor-server-host-common-jvm.1.6.5.jar at folder io.ktor.server.engine, inside the file ApplicationEngineEnvironmentReloading.kt is trying to filter the URL's obtained from the class path:
line 163
val allUrls = baseClassLoader.allURLs()
And it's trying to filter the url's using the patterns configured in my application.conf
watch = [classes, resources]
After filter all content, at line 193
watchUrls(watchUrls)
still reaming one URL with the format "jar:file:/...." and that line is generating the error.
Thank you!
can get file from formdata with multiple files
<form action="/upload" method="post">
<input type="file" name="test1" id="test1" multiple>
</form>
form.forEachPart {
when (it) {
is PartData.FileItem -> {
when (it.name) {
"test1" -> fileBytes = it.streamProvider().readBytes()
}
}
}
}
if user choose upload multiple files, the stream only contains the first file, and others will be lost.
Ktor Server and double receive break receiving of big files
In case if receiveEntireContent
of DoubleReceive
feature has been setup to true
function readPart
of MutliPartData
will take a lot of time:
Installing example:
install(DoubleReceive) {
receiveEntireContent = true
}
Some routing example:
val multipart = call.receiveMultipart()
multipart.readPart() // in case if here should be FileItem it take a lot of time to handle it
// ...
Error with Koin DI in Ktor version 1.6.6+
When adding modules for dependency injection with Koin (using latest version 3.1.4) there is a weird bug in versions 1.6.6+
Here's my repo. This error can easily be mitigated by migrating down to Ktor version 1.6.5 and under, and only surfaces in 1.6.6 and higher.
Here's is a link to the branch where I added it and had to migrate my Ktor version down: https://github.com/JimmyMcBride/boruto-server/tree/19-create_all_heroes_endpoint_p1
Exception in thread "main" java.lang.NoSuchMethodError: 'double kotlin.time.Duration.toDouble-impl(long, java.util.concurrent.TimeUnit)'
at org.koin.core.time.MeasureKt.measureDuration(Measure.kt:32)
at org.koin.core.KoinApplication.modules(KoinApplication.kt:59)
at org.koin.core.KoinApplication.modules(KoinApplication.kt:42)
at com.example.plugins.KoinKt$configureKoin$1.invoke(Koin.kt:11)
at com.example.plugins.KoinKt$configureKoin$1.invoke(Koin.kt:9)
at org.koin.core.context.GlobalContext.startKoin(GlobalContext.kt:64)
at org.koin.core.context.DefaultContextExtKt.startKoin(DefaultContextExt.kt:31)
at org.koin.ktor.ext.Koin$Feature.install(KoinFeature.kt:48)
at org.koin.ktor.ext.Koin$Feature.install(KoinFeature.kt:42)
at io.ktor.application.ApplicationFeatureKt.install(ApplicationFeature.kt:68)
at com.example.plugins.KoinKt.configureKoin(Koin.kt:9)
at com.example.ApplicationKt.module(Application.kt:11)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Static.call(CallerImpl.kt:106)
at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:159)
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
at io.ktor.server.engine.internal.CallableUtilsKt.callFunctionWithInjection(CallableUtils.kt:119)
at io.ktor.server.engine.internal.CallableUtilsKt.executeModuleFunction(CallableUtils.kt:36)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$launchModuleByName$1.invoke(ApplicationEngineEnvironmentReloading.kt:332)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$launchModuleByName$1.invoke(ApplicationEngineEnvironmentReloading.kt:331)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.avoidingDoubleStartupFor(ApplicationEngineEnvironmentReloading.kt:356)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.launchModuleByName(ApplicationEngineEnvironmentReloading.kt:331)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.access$launchModuleByName(ApplicationEngineEnvironmentReloading.kt:30)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$instantiateAndConfigureApplication$1.invoke(ApplicationEngineEnvironmentReloading.kt:312)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$instantiateAndConfigureApplication$1.invoke(ApplicationEngineEnvironmentReloading.kt:310)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.avoidingDoubleStartup(ApplicationEngineEnvironmentReloading.kt:338)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:310)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:143)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:277)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:174)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:26)
at com.example.ApplicationKt.main(Application.kt:7)
Process finished with exit code 1
Make default charset UTF-8 when using `receiveText` for application/json request
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/384
This is a follow up to #80. Apparently, responses were fixed, but there are still issues with the requests.
Request with Content-Type: application/json
is decoded not as UTF-8, while request with Content-Type: application/json; charset=utf-8
is decoded correctly. Both has to behave the same and be decoded as UTF-8.
Routing is called for handled requests
GSON ContentNegotiation ignores charset
Currently I am doing the following:
install(ContentNegotiation) {
gson(ContentType.Application.Json.withCharset(Charset.forName("UTF-8"))) {
registerTypeAdapter(Instant::class.java, InstantTypeConverter()) // not related
}
}
However, when I inspect the response in the browser, I see the following:
Accept
application/json, text/plain, */*
Accept-Encoding
gzip, deflate
Accept-Language
vi-VN,vi;q=0.8,en-US;q=0.5,en;q=0.3
Connection
keep-alive
Content-Length
176
Content-Type
application/json
The charset is missing from Content-Type
as well as Accept
. This causes encoding issues. For example, I get back Végh
instead of Végh
Other
Binary compatibility issue with Ktor 1.6.5 (affecting JDK 1.8 & 11 users)
I haven't checked the details yet but some tests using Ktor's testing module in our project detected a binary-compatibility issue.
As a workaround, we locked the version to 1.6.4 and it worked for us. https://github.com/slackapi/java-slack-sdk/commit/8a9063bf694376074a3a4bed93871416f48241c3
I hope this helps.
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231)
at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAsMuchAsPossible(ByteBufferChannel.kt:3487)
at io.ktor.utils.io.ByteBufferChannel.writeFully$suspendImpl(ByteBufferChannel.kt:1425)
at io.ktor.utils.io.ByteBufferChannel.writeFully(ByteBufferChannel.kt)
at io.ktor.utils.io.ByteWriteChannelKt.writeFully(ByteWriteChannel.kt:152)
at io.ktor.server.engine.BaseApplicationResponse$respondFromBytes$3$1.invokeSuspend(BaseApplicationResponse.kt:191)
at (Coroutine boundary.()
at io.ktor.server.engine.DefaultTransformKt$installDefaultTransformations$1.invokeSuspend(DefaultTransform.kt:35)
at test_locally.app.events.TestKt$main$2$1.invokeSuspend(test.kt:42)
at io.ktor.routing.Routing.executeResult(Routing.kt:154)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:107)
at io.ktor.server.testing.TestApplicationEngine$callInterceptor$1.invokeSuspend(TestApplicationEngine.kt:296)
at io.ktor.server.testing.TestApplicationEngine$2.invokeSuspend(TestApplicationEngine.kt:50)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$pipelineJob$1.invokeSuspend(TestApplicationEngine.kt:295)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$1.invokeSuspend(TestApplicationEngine.kt:153)
API Docs reference RFCs. Better to reference our own documentation
Many plugins reference RFCs, such as the one for ForwardedHeaders or AuthScheme, and yet it would make sense to reference our own documentation (which in turn actually references RFCs'). This should be applied consistently across the entire code base.
Add YAML Configuration Format Support
Right now we're supporting automatically only hocon
configuration format(with application.conf
file located in the resources folder). Unfortunately, this format is supported only with using external plugins so it's hard to provide any navigation features.
As the solution, we want to have the YAML support(same as HOCON) with a brief review of the API on how to fetch properties.
Rewrite Thymeleaf to New Plugins API
Rewrite CachingHeaders to New Plugins API
Implementation for Single Page Plugin
Implementation for Single Page Plugin
Ktor 1.5.0 failed to upload multipart form data
I am using Ktor version 1.5.0. and when I try to upload multipart form data, getting server exception(500 error) with the following error.
{
"stack": "TypeError: Cannot read property 'name' of undefined\n at FormData._getContentDisposition (/var/www/app/node_modules/form-data/lib/form_data.js:226:40)\n at FormData._multiPartHeader (/var/www/app/node_modules/form-data/lib/form_data.js:177:33)\n at FormData.append (/var/www/app/node_modules/form-data/lib/form_data.js:70:21)\n at Object.createTicketResponse (/var/www/app/api/services/JarvisService.js:105:7)\n at Object.wrapper [as createTicketResponse] (/var/www/app/node_modules/@sailshq/lodash/lib/index.js:3282:19)\n at Object.createTicketResponse [as apiv1/createticketresponse] (/var/www/app/api/controllers/ApiV1Controller.js:215:18)\n at /var/www/app/node_modules/sails/lib/router/bind.js:236:53\n at routeTargetFnWrapper (/var/www/app/node_modules/sails/lib/router/bind.js:395:9)\n at Layer.handle [as handle_request] (/var/www/app/node_modules/express/lib/router/layer.js:95:5)\n at next (/var/www/app/node_modules/express/lib/router/route.js:137:13)\n at Route.dispatch (/var/www/app/node_modules/express/lib/router/route.js:112:3)\n at Layer.handle [as handle_request] (/var/www/app/node_modules/express/lib/router/layer.js:95:5)\n at /var/www/app/node_modules/express/lib/router/index.js:281:22\n at param (/var/www/app/node_modules/express/lib/router/index.js:354:14)\n at param (/var/www/app/node_modules/express/lib/router/index.js:365:14)\n at param (/var/www/app/node_modules/express/lib/router/index.js:365:14)\n at Function.process_params (/var/www/app/node_modules/express/lib/router/index.js:410:3)\n at next (/var/www/app/node_modules/express/lib/router/index.js:275:10)\n at next (/var/www/app/node_modules/express/lib/router/route.js:127:14)\n at module.exports (/var/www/app/api/policies/isUser.js:6:2)\n at routeTargetFnWrapper (/var/www/app/node_modules/sails/lib/router/bind.js:395:9)\n at Layer.handle [as handle_request] (/var/www/app/node_modules/express/lib/router/layer.js:95:5)\n at next (/var/www/app/node_modules/express/lib/router/route.js:137:13)\n at Route.dispatch (/var/www/app/node_modules/express/lib/router/route.js:112:3)\n at Layer.handle [as handle_request] (/var/www/app/node_modules/express/lib/router/layer.js:95:5)\n at /var/www/app/node_modules/express/lib/router/index.js:281:22\n at param (/var/www/app/node_modules/express/lib/router/index.js:354:14)\n at param (/var/www/app/node_modules/express/lib/router/index.js:365:14)",
"message": "Cannot read property 'name' of undefined",
"sentry_captured": true
}
and the backend receiving the request body as below. in request, key is receiving as null.
he req body as follows. key params are receiving as null. {"null":["Some description","�PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR\u0000\u0000\u0000\u000b\u0000\u0000\u0000\u000b\b\u0002\u0000\u0000\u0000&��q\u0000\u0000\u0000\u0001sRGB\u0000��\u001c�\u0000\u0000\u0000DeXIfMM\u0000*\u0000\u0000\u0000\b\u0000\u0001�i\u0000\u0004\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u001a\u0000\u0000\u0000\u0000\u0000\u0003�\u0001\u0000\u0003\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000�\u0002\u0000\u0004\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u000b�\u0003\u0000\u0004\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u000b\u000�\u0004���\u0000\u0000\u0000\u0000��4F"M\u0000\u0000\u0000GIDATm�A\u0011\u0000 \b\u0004M\u0005�HB\u0001�a\u0002\u0012���A�}��cD��!"D\u00043�31;�\n��X��C�Po\u000743���]\u001dxgf]#�\u0000�0$�L���\u0000\u0000\u0000\u0000IEND�B�"]}
my code is in below
HTTPClientService().httpClient.post(url) {
headers {
append(HttpHeaders.Authorization, token)
}
body = MultiPartFormDataContent(
formData {
append("description", "Some description")
append("media",createTicketRequest.media.toByteArray(), Headers.build { append(HttpHeaders.ContentType, "image/jpeg")
append(HttpHeaders.ContentDisposition, "filename=${createTicketRequest.media}.jpeg")
})
}
)
is any fix for this?
kotlinx.coroutines.channels.ClosedReceiveChannelException: Channel was closed on Xiaomi Redmi 8, Android 10, only when SSL is enabled
I see the following exception on an Android 10 Redmi 8 phone when making a get request to a Ktor server running on another device:
kotlinx.coroutines.channels.ClosedReceiveChannelException: Channel was closed
at kotlinx.coroutines.channels.Closed.getReceiveException(AbstractChannel.kt:1108)
at kotlinx.coroutines.channels.AbstractChannel$ReceiveElement.resumeReceiveClosed(AbstractChannel.kt:913)
at kotlinx.coroutines.channels.AbstractChannel.receiveSuspend(AbstractChannel.kt:609)
at kotlinx.coroutines.channels.AbstractChannel.receive(AbstractChannel.kt:593)
at kotlinx.coroutines.channels.ChannelCoroutine.receive(Unknown Source:2)
at io.ktor.network.tls.TLSClientHandshake$handshakes$1.invokeSuspend(TLSClientHandshake.kt:134)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
The server is a Ktor server hosted on another Android device.
Sever engine: Netty
Client Engine: CIO
The issue only happens if SSL is enabled on the server.
I have only experienced this with the Xiaomi Redmi device, and I have tested quite a wide range of devices.
Any ideas?
[netty] Cancelled websocket scope never gets closed
So I get that I'm doing something weird here since I'm trying to conditionally handshake websocket connections, but I think the issue may be real? I can't reproduce it any other way, so if there's an alternative to make conditional handshaking work, I'd totally take that too.
The issue is that cancelling a pipeline execution can leave the websocket connection open, but indefinitely stuck (until the client closes the connection). This is rather easily demonstrated by the following code:
suspend fun ApplicationCall.redirectInternally(path: String, subject: Unit) {
val cp = object : RequestConnectionPoint by this.request.local {
override val uri: String = path
}
val req = object : ApplicationRequest by this.request {
override val local: RequestConnectionPoint = cp
}
val call = object : ApplicationCall by this {
override val request: ApplicationRequest = req
}
this.application.execute(call, subject)
}
get("/ws") {
val job = launch {
call.redirectInternally("/ws/internal", Unit) // cond
}
delay(100) // wait for handshake
job.cancel()
}
webSocket("/ws/internal") {
try {
delay(3000) // do work
} finally {
this.close() // No effect since SendChannel is cancelled
}
}
I've debugged this to the SendChannel getting cancelled with the context cancellation, yet the connection isn't closed beforehand. When the ktor connection management tries to send its Close frame, the SendChannel just bails out. withContext(NonCancellable) and sending a manual close frame doesn't help either, since the channel stores the original closedForSend exception locally.
Cancelling the socket from within the webSocket handler works totally fine - it's only an issue when it's cancelled by the parent job.
This also only impacts the Netty engine, CIO closes the websocket with a 1000 status code (internally, explicit closes aren't necessary/don't have an effect either). Not sure about other engines.
POST request to database returns 403 error
I made a web app using Ktor following this tutorial.
This app uses Ktor for the server, Kotlin/JS for the frontend, and MongoDB for the database.
I am now trying to deploy this app on Heroku and used MongoDB Atlas for the remote database.
But, whenever I try to perform a POST request through the app, it returns the following error:
ClientRequestException {message_8yp7un$_0: 'Bad response: HttpResponse[https://stormy-scrublan…okuapp.com/shoppingList, 403 Forbidden]. Text: ""', cause_th0jdv$_0: null, name: 'ClientRequestException', _response_kjamci$_h84ynm$_0: ReadOnlyProperty, message_mrabda$_0: 'Client request(https://stormy-scrubland-72901.hero…om/shoppingList) invalid: 403 Forbidden. Text: ""', …}
cause_th0jdv$_0: null
message_8yp7un$_0: "Bad response: HttpResponse[https://stormy-scrubland-72901.herokuapp.com/shoppingList, 403 Forbidden]. Text: \"\""
message_mrabda$_0: "Client request(https://stormy-scrubland-72901.herokuapp.com/shoppingList) invalid: 403 Forbidden. Text: \"\""
name: "ClientRequestException"
_response_kjamci$_h84ynm$_0: ReadOnlyProperty {function$: ƒ}
stack: "ClientRequestException: Client request(https://stormy-scrubland-72901.herokuapp.com/shoppingList) invalid: 403 Forbidden. Text: \"\"\n at Object.captureStack (webpack-internal:///./kotlin-dce-dev/kotlin.js:38600:15)\n at ClientRequestException.Exception [as constructor] (webpack-internal:///./kotlin-dce-dev/kotlin.js:38933:14)\n at ClientRequestException.RuntimeException [as constructor] (webpack-internal:///./kotlin-dce-dev/kotlin.js:38959:17)\n at ClientRequestException.IllegalStateException [as constructor] (webpack-internal:///./kotlin-dce-dev/kotlin.js:38999:24)\n at IllegalStateException_init_0 (webpack-internal:///./kotlin-dce-dev/kotlin.js:39010:29)\n at ClientRequestException.ResponseException [as constructor] (webpack-internal:///./kotlin-dce-dev/ktor-ktor-client-core-js-legacy.js:2631:5)\n at new ClientRequestException (webpack-internal:///./kotlin-dce-dev/ktor-ktor-client-core-js-legacy.js:2701:23)\n at Coroutine$addDefaultResponseValidation$lambda$lambda.doResume (webpack-internal:///./kotlin-dce-dev/ktor-ktor-client-core-js-legacy.js:2592:17)\n at Coroutine$trySuspend_0.CoroutineImpl.resumeWith_tl1gpc$ (webpack-internal:///./kotlin-dce-dev/kotlin.js:38771:35)\n at CancellableContinuationImpl.DispatchedTask.run (webpack-internal:///./kotlin-dce-dev/kotlinx-coroutines-core.js:28941:22)"
cause: (...)
message: (...)
response: (...)
_response_kjamci$_0: (...)
[[Prototype]]: ResponseException
Strangely, when performing a POST request through IntelliJ IDEA, it works perfectly fine returning 200 OK.
GET and DELETE request also performs as it should.
This is the code that performs the request:
suspend fun addShoppingListItem(shoppingListItem: ShoppingListItem) {
jsonClient.post<Unit>(endpoint + ShoppingListItem.path) {
contentType(ContentType.Application.Json)
body = shoppingListItem
}
}
And this is the code that handles the request:
route(ShoppingListItem.path) {
get {
call.respond(collection.find().toList())
}
post {
collection.insertOne(call.receive<ShoppingListItem>())
call.respond(HttpStatusCode.OK)
}
delete("/{id}") {
val id = call.parameters["id"]?.toInt() ?: error("Invalid delete request")
collection.deleteOne(ShoppingListItem::id eq id)
call.respond(HttpStatusCode.OK)
}
}
I don't have a clue why this is happening, and thinking this might be a bug.
Thanks.
iOS HttpClient NSURLSessionAuthChallengeDisposition type error issue
Hi, I have an issue on iOS side when trying HttpClient with iOS engine.
I tried the following code:
HTTPClient(Ios){
engine{
handleChallenge { session, task, challenge, completionHandler ->
completionHandler(NSURLSessionAuthChallengeUseCredential, null)
}
}
}
However, when I build it, the build failed. NSURLSessionAuthChallengeUseCredential despite inheriting from NSURLSessionAuthChallengeDisposition is a type of Kotlin.Long, but the completion handler’s first param only take NSURLSessionAuthChallengeDisposition which is a type of platform.darwin.NSInteger. I tried converting NSURLSessionAuthChallengeUseCredential to int and at the build has no error, but when building it on Xcode, the following error appeared when the build failed:
Type mismatch: inferred type is Int but NSURLSessionAuthChallengeDisposition /* = Long */ was expected
The issue, I think, is on the completionHandler taking only platform.darwin.NSInteger, which caused this issue on Xcode. I would appreciate any help or explanation of this error.
I also made a thread on stack overflow regarding this issue:
Thank you for your attention.
Trouble with ktor on native
I'm currently trying to create an application with kt/native for an rpi 0 but I want to be able to view data from the application from a web interface so I'm trying to use compose as my kt/js front end. I was wanting to use ktor as the web backend because I heard that as of 1.1.2 it supported kt/native but I was running into trouble and heard again that it's only supported in the eap releases so I tried that but still I'm running into trouble. Am I miss understanding and ktor doesn't support kt/native yet or am I doing something wrong
build.gradle.kts
:
plugins {
kotlin("multiplatform") version "1.5.31"
id("org.jetbrains.compose") version "1.0.0"
id("jaci.gradle.EmbeddedTools") version "2020.12.23"
}
repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/ktor/eap")
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
kotlin {
js("client", IR) {
binaries.executable()
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
linuxX64("linux") {
binaries.executable() {
entryPoint = "main"
}
}
linuxArm32Hfp("rpi") {
binaries.executable() {
entryPoint = "main"
}
}
sourceSets {
val commonMain by getting {
}
val clientMain by getting {
dependencies {
implementation(compose.web.core)
}
}
val linuxMain by getting {
dependencies {
implementation("io.ktor:ktor-server-core:2.0.0-eap-332")
implementation("io.ktor:ktor-server-netty:2.0.0-eap-332")
implementation("io.ktor:ktor-html-builder:2.0.0-eap-332")
}
}
val rpiMain by getting {
}
}
}
output:
<> Task :compileKotlinLinux FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileKotlinLinux'.
> Could not resolve all files for configuration ':linuxCompileKlibraries'.
> Could not find org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20-M1-106.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
Required by:
project :
> Could not resolve io.ktor:ktor-server-netty:2.0.0-eap-332.
Required by:
project :
> No matching variant of io.ktor:ktor-server-netty:2.0.0-eap-332 was found. The consumer was configured to find a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native', attribute 'org.jetbrains.kotlin.native.target' with value 'linux_x64' but:
- Variant 'commonMainMetadataElements' capability io.ktor:ktor-server-netty:2.0.0-eap-332 declares a usage of 'kotlin-api' of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'common' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'linux_x64')
- Variant 'jvmApiElements-published' capability io.ktor:ktor-server-netty:2.0.0-eap-332 declares an API of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'linux_x64')
- Variant 'jvmRuntimeElements-published' capability io.ktor:ktor-server-netty:2.0.0-eap-332 declares a runtime of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'linux_x64')
- Variant 'metadataApiElements' capability io.ktor:ktor-server-netty:2.0.0-eap-332:
- Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'common' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'linux_x64')
> Could not find io.ktor:ktor-html-builder:2.0.0-eap-332.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-html-builder/2.0.0-eap-332/ktor-html-builder-2.0.0-eap-332.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-html-builder/2.0.0-eap-332/ktor-html-builder-2.0.0-eap-332.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/io/ktor/ktor-html-builder/2.0.0-eap-332/ktor-html-builder-2.0.0-eap-332.pom
Required by:
project :
> Could not find org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20-M1-106.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
Required by:
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-utils:2.0.0-eap-332 > io.ktor:ktor-utils-linuxx64:2.0.0-eap-332
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-http:2.0.0-eap-332 > io.ktor:ktor-http-linuxx64:2.0.0-eap-332
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-serialization:2.0.0-eap-332 > io.ktor:ktor-serialization-linuxx64:2.0.0-eap-332
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-events:2.0.0-eap-332 > io.ktor:ktor-events-linuxx64:2.0.0-eap-332
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-utils:2.0.0-eap-332 > io.ktor:ktor-utils-linuxx64:2.0.0-eap-332 > io.ktor:ktor-io:2.0.0-eap-332 > io.ktor:ktor-io-linuxx64:2.0.0-eap-332
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-serialization:2.0.0-eap-332 > io.ktor:ktor-serialization-linuxx64:2.0.0-eap-332 > io.ktor:ktor-websockets:2.0.0-eap-332 > io.ktor:ktor-websockets-linuxx64:2.0.0-eap-332
> Could not find org.jetbrains.kotlin:kotlin-reflect:1.6.20-M1-106.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-reflect/1.6.20-M1-106/kotlin-reflect-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/org/jetbrains/kotlin/kotlin-reflect/1.6.20-M1-106/kotlin-reflect-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/kotlin/kotlin-reflect/1.6.20-M1-106/kotlin-reflect-1.6.20-M1-106.pom
Required by:
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332
> Could not find org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20-M1-106.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
- https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20-M1-106/kotlin-stdlib-common-1.6.20-M1-106.pom
Required by:
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > org.jetbrains.kotlinx:atomicfu:0.17.0 > org.jetbrains.kotlinx:atomicfu-linuxx64:0.17.0
project : > io.ktor:ktor-server-core:2.0.0-eap-332 > io.ktor:ktor-server-core-linuxx64:2.0.0-eap-332 > io.ktor:ktor-utils:2.0.0-eap-332 > io.ktor:ktor-utils-linuxx64:2.0.0-eap-332 > org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0 > org.jetbrains.kotlinx:kotlinx-coroutines-core-linuxx64:1.6.0
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.9.2/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 5s
15 actionable tasks: 2 executed, 13 up-to-date
<-------------> 0% WAITING
> IDLE
throw BadeRequest instead of Internal Server when request data is not correct
What steps will reproduce the issue?
1. create a route and give a generic;
2. post data from client with incorrect data
3. got 500
What is the expected result?
got 400 instead of 500
What happens instead?
got error code with 500
further more
if generic like
data class (val id:Int?,val name:Int?)
and the data is {id:50}
, it will also cause an error, but , I expect to get this data
`resources` routing is not working inside bootJar
I use org.springframework.boot
gradle plugin for packing ktor application into single jar, however resolution of resources does not work in nested jars.
embeddedServer(Netty, host = config.server.host, port = config.server.port) {
// ...
routing {
// ...
static("/") {
resources("static")
}
}
}
I would say resourceClasspathResource
function is guilty as it uses custom mechanism for loading resources and doesn't handle nested jars.
Websocket is closed continually in Android
I am trying to create websocket in Android 6.0, it works fine in debug but websocket is closed continually in release mode. I have two different applications and it happens only one of them. I am using Netty, but tried with CIO and got same result. I am using ReconnectingWebSocket in client side and it catches closed event reason as undefined. I also tried with Ktor-2.0.0-beta-1 it hangs on for the index.html. I tried debugging in ktor WebSocket but could not catch any useful info. What could cause this problem?
Server crashed the Android app when network switch off
Server:
private val ipAddress = ipAddressProvider.getLocalIpAddress()
private val server by lazy {
embeddedServer(
factory = CIO,
port = port,
host = ipAddressProvider.getLocalIpAddress()
) {
install(WebSockets)
routing {
webSocket("/ws") {
// ...
}
static("/") {
// ...
}
}
}
}
fun launch() = coroutineScope.launch(Dispatchers.IO) {
server.start(true)
}
...
class IpAddressProvider(private val context: Context) {
fun getLocalIpAddress(): String {
val wifiManager =
context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
return Formatter.formatIpAddress(wifiManager.connectionInfo.ipAddress)
}
}
Server launches in Android application, if switch off wifi or wireless connection, app crashes with exception:
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-3
Process: ..., PID: ...
java.io.IOException: Invalid argument
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
at io.ktor.network.sockets.ServerSocketImpl.acceptSuspend(ServerSocketImpl.kt:35)
at io.ktor.network.sockets.ServerSocketImpl.access$acceptSuspend(ServerSocketImpl.kt:12)
at io.ktor.network.sockets.ServerSocketImpl$acceptSuspend$1.invokeSuspend(Unknown Source:14)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Ktor version 1.6.7
How to process this exception or any workaround to prevent crash and stop the server?
Adding a dependency on kotlinx-serialization-core:1.3.0 and up crashes kmm library builds when using kotlin 1.6.10
I noticed during the migration of my kmm library to kotlin 1.6.10 that having org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.0
makes the build crash with the following error :
e: Compilation failed: null
* Source files:
* Compiler version info: Konan: 1.6.10 / Kotlin: 1.6.10
* Output kind: FRAMEWORK
e: java.lang.NullPointerException
at org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR$SymbolTable.mapClassReferenceType(DataFlowIR.kt:520) ...
The crashes can be fixed by downgrading to org.jetbrains.kotlinx:kotlinx-serialization-core:1.2.2
.
There's a thread about this issue here https://kotlinlang.slack.com/archives/C3PQML5NU/p1641817165062900
io.ktor.application.MissingApplicationFeatureException: Application feature Authentication is not installed
When i am trying to run the below code from intellij starter project.
import io.ktor.auth.*
import io.ktor.auth.ldap.*
import io.ktor.application.*
fun Application.configureSecurity() {
val localhost = "http://0.0.0.0"
val ldapServerPort = 6998 // TODO: change to real value!
authentication {
basic("authName") {
realm = "realm"
validate { credential ->
ldapAuthenticate(credential, "ldap://$localhost:${ldapServerPort}", "uid=%s,ou=system")
}
}
}
}
error is
Exception in thread "main" io.ktor.application.MissingApplicationFeatureException: Application feature Authentication is not installed
at io.ktor.application.ApplicationFeatureKt.feature(ApplicationFeature.kt:44)
at io.ktor.auth.AuthenticationKt.authenticate(Authentication.kt:317)
at io.ktor.auth.AuthenticationKt.authenticate$default(Authentication.kt:308)
Locking ios device with socket connection active causes app to crash upon device unlock
Versions:
kotlinVersion=1.6.10
coroutinesBaseVersion=1.5.1-new-mm-dev2
ktorVersion=1.6.7
rsocketVersion=0.14.3
serializationVersion=1.3.0
We have a Kotlin multiplatform project targeting ios and android. We are communicating with our server via RSocket.
Everything works fine until you lock the device. After unlocking it, it just says:
Message from debugger: Terminated due to signal 13
@olme04 pointed me to this issue and adding signal(SIGPIPE, SIG_IGN) //Ignore signal
workarounds the issue.
His answer can be found here.
Let me know if some more details is needed from me.
Ktor socket in android bug
I used Ktor for DIY development, in the Ktor server back end can perception disconnection from the network, awaitContent,awaitClosed can success return from suspension, but in android disconnection from the network, these methods can not return.
Gitee :https://gitee.com/slientes/custom-ktor
Ktor version:1.6.0
post path instruction not included in Jacoco test report.
Normally my routes are included in Jacoco test reports. However, if call another request inside the route with Ktor client, the post path is not included:
^^ post path is yellow
If I remove the nested request, then request path shows covered like expected.
I tested with Kover and that one shows the post instruction as tested, even with the client request:
How should I implement my nested request inside this handler so the Jacoco reports shows it as covered?
ktor:1.6.7
kotlin:1.6.10
Rename the 'header' function to 'allowHeader' for consistency with similar functions
The header
function manages the Access-Control-Allow-Headers
response header. There is also allowHeadersPrefixed
and allowHeaders
functions that manage the same header. It would be logical to rename header
to allowHeader
to make names more consistent.
Memory leak when Compression plugin is installed
The Deflater implementation is causing memory leaks when the response channel gets closed (for example when a peer resets the connection) and the gzipped content is larger than the ByteBufferChannel backing buffer (4088).
More exactly this happens for the ByteWriteChannel.deflated method which launches 2 coroutines, one that is reading the uncompressed body and is executing the compression, and one that is copying the compressed body in the response channel. The one which is doing the copying will close since the copyTo method throws the error when it cannot write and the coroutines stops but it is not terminated with exception as it is caught by the launchChannel code, so no cancellation is propagated. The coroutine which executes the compression will continue to run and could notice that the input channel (the one with the uncompressed body data) is closed and will exit, but in the case where compressed size is bigger than the buffer size (4088), it will enter in suspension and since nobody is there to consume the data, it will never be resumed.
This will cause 3 coroutines to remain hanging and never terminate, I attached a file with them and their stack traces.
I also attached a test which replicates the issue and remains hanging.
Youtrack: Add 1.6.8
Ktor test websocket call hangs
We have a test that checks the authentication in a Web Socket route. The route will return a non 200 status code with an error body in this case. When attempting to test this route using the test application the test hangs indefinitely as demonstrated here:
fun Application.testModule() {
routing {
// In our actual code this is a websocket route but it can respond with a non 200 error code
get("/test") {
call.respondOutputStream(status = HttpStatusCode.Forbidden) {
write(ByteArray(1024 * 1024))
}
}
}
}
withTestApplication({ testModule() }) {
val regularCall = handleRequest(HttpMethod.Get, "/test") {}
println("Regular call returned ${regularCall.response.status()}")
val wsCall = handleWebSocket("/test") {}
println("WS call returned ${wsCall.response.status()}")
}
The test hangs when ktor is trying to write the response body in the second case. If the body is small then it completes successfully.
Remove mutex from call logging
https://ktor.io/create/ – "Gradle Groovy" and "Gradle Kotlin" are the wrong way around
The above is Groovy syntax (no parens), but shown as Kotlin syntax.
The above is Kotlin syntax (parens) but shown as Groovy syntax.
Rename ApplicationPlugin<A, B, C> to BaseApplicationPlugin<A, B, C>
Test new 'docs required' workflow (ADM-66561)
testApplication: Add https EngineConnector
With KTOR-3614 the testApplication
supports https calls to the internal TestEngine
, but only if the requested port is explicit set to 80
. This requires to set the host of a request to https://localhost:80/foo
.
Expected: https://localhost/foo
Solution: Add a second connector listen on the default https
port 443
.
Rewrite HttpsRedirect to New Plugins API
Rewrite WebJars to New Plugins API
Rewrite Metrics to New Plugins API
Rewrite PartialContent to New Plugins API
Drop Before/After from new plugins API
Add DslMarker to testApplication builder
Ktor Kotlin Multiplatform leak
Hi guys, every time I make a request with ktor
from my native part (iOS) I get leaks like these:
Could help me go deeper, and get the reason why of these leaks?
Library versions:
object Versions {
const val iosTestTask = false
const val foo = "8.6.8"
const val kotlin = "1.5.31"
// Gradle
const val androidGradlePlugin = "7.0.2"
const val gradle = "gradle-7.2-bin"
// Android
const val compileSdk = 31
const val minSdk = 23
const val targetSdk = compileSdk
// You can also use this to specify versions for dependencies. Having consistent
// versions between modules can avoid behavior conflicts.
const val sqldelight = "1.5.1"
const val settings = "0.8"
const val serialization = "1.2.2"
// https://kotlinlang.org/docs/mobile/concurrency-and-coroutines.html#multithreaded-coroutines
const val coroutines = "1.5.1-native-mt"
const val ktor = "1.6.3"
const val openapigen = "5.3.0"
}
I've a coroutine presenter like this:
open class CoroutinePresenter(
private val mainContext: CoroutineContext = ApplicationDispatcher
): CoroutineScope {
private val job = Job()
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
print(throwable)
}
override val coroutineContext: CoroutineContext
get() = mainContext + job + exceptionHandler
open fun cancelRequest() {
cancel()
}
open fun onDestroy() {
print("CoroutinePresenter onDestroy: cancel job!")
job.cancel()
}
}
As ApplicationDispatcher
I wrote:
internal actual val ApplicationDispatcher: CoroutineContext = MainDispatcher()
internal class MainDispatcher : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatch_async(dispatch_get_main_queue()) { block.run() }
}
}
And I use Presenters
like that:
@Suppress("UNUSED")
open class BasePresenter(
apiService: ApiService
) : CoroutinePresenter() {
open val service: WeakRef<ApiService> = WeakRef(apiService)
open val jsonSerilizer = Json {
isLenient = true
}
open class BaseRequestViewState(
val apiErrorMessage: String? = null,
val statusCode: Int? = null,
val errorType: ErrorMessage.ErrorType? = null,
val unexpectedError: String? = null,
val indicatorAnimating: Boolean = false,
val requestSucceeded: Boolean = false,
val validationSucceeded: Boolean = false
)
open suspend fun <T : BaseRequestViewState, M : Any> requestAsync(
returnT: (BaseRequestViewState) -> T,
initialViewStateHandler: (T) -> Unit,
appSettings: AppSettings,
retrieveFromDb: (() -> T?)? = null,
apiCall: suspend (ApiService) -> HttpResponse<M>,
successfulHandler: (M) -> T,
validationCall: (() -> T)? = null
): T {
validationCall?.let {
val validationViewState = it()
if (!validationViewState.validationSucceeded) {
return validationViewState
}
}
initialViewStateHandler(
returnT(
BaseRequestViewState(
indicatorAnimating = true
)
)
)
retrieveFromDb?.let {
val dbViewState = it()
dbViewState?.let {
return it
}
}
// WARNING - https://github.com/ktorio/ktor/issues/1165
return try {
// OKAY - MAKE SINGLETON
if (service.get() == null) {
returnT(
BaseRequestViewState(
requestSucceeded = false,
unexpectedError = "Weak reference service is null|"
)
)
}
val service = this.service.get()!!
val response = apiCall(service)
val statusCode = response.status
val headers = response.headers
print("headers: $headers")
pintln("--> K-side Status code: $statusCode")
if (successStatusCode(statusCode)) {
when (statusCode) {
200 -> {
// only here we return the actual T class
return successfulHandler(response.body())
}
else -> {
returnT(
BaseRequestViewState(
apiErrorMessage = "Unexpected error for status code: $statusCode",
requestSucceeded = false,
statusCode = statusCode
)
)
}
}
} else {
handleManagedServerError(headers, statusCode, appSettings, returnT)
}
} catch (cre: ClientRequestException) { // 400..499
val headers = cre.response.headers.toMap()
val statusCode = cre.response.status.value
handleManagedServerError(headers, statusCode, appSettings, returnT)
} catch (sre: ServerResponseException) { // 500..599
val statusCode = sre.response.status.value
val message = "Errore del server: $statusCode"
handleKtorResponseException(returnT, message)
} catch (rre: RedirectResponseException) { // 300..399
val statusCode = rre.response.status.value
val message = "Errore di redirect: $statusCode"
handleKtorResponseException(returnT, message)
} catch (re: ResponseException) {
val statusCode = re.response.status.value
val message = "Errore generico di risposta: $statusCode"
handleKtorResponseException(returnT, message)
} catch (exception: Exception) {
returnT(
BaseRequestViewState(
apiErrorMessage = ErrorManager.apiErrorMessage(
serverError = exception.message ?: ""
)
)
)
} catch (throwable: Throwable) {
returnT(
BaseRequestViewState(
apiErrorMessage = ErrorManager.apiErrorMessage(
serverError = throwable.message ?: ""
)
)
)
}
}
private fun <T : BaseRequestViewState> handleKtorResponseException(
returnT: (BaseRequestViewState) -> T,
message: String
) = returnT(
BaseRequestViewState(
apiErrorMessage = ErrorManager.apiErrorMessage(
serverError = message
)
)
)
private fun <T : BaseRequestViewState> handleManagedServerError(
headers: Map<String, List<String>>,
statusCode: Int,
appSettings: AppSettings,
returnT: (BaseRequestViewState) -> T
): T {
val serverError = handleServerError(headers, statusCode, appSettings)
val localizedErrorMessage = serverError.first
val errorType = serverError.second
print("K-side --> localizedMessage: $localizedErrorMessage, $errorType")
return returnT(
BaseRequestViewState(
apiErrorMessage = localizedErrorMessage,
statusCode = statusCode,
errorType = errorType
)
)
}
override fun onDestroy() {
super.onDestroy()
println("K side - ${this::class} onDestroy!")
this.service.clear()
}
}
It's not easy to make a minimal working example because the HTTP client is generated from a swagger template.
I just started to investigate, but if you already have any clue, please let me know.
Rewrite Compression to New Plugins API
Rewrite Auto Head to New Plugins API
Rewrite DoubleReceive to New Plugins API
Rewrite CORS to New Plugins API
Rewrite Auth to New Plugins API
Rewrite Sessions to New Plugins API
Rewrite ContentNegotiation to New Plugins API
Rewrite MethodOverride to New Plugins API
Update logback and slf4j
ByteBufferChannel leaves unflushed data after partial readAvailable causing Apache client request to stall
We're observing rare but recurring timeouts in production on Apache client requests with content lengths > 4KB (presumably 4088 bytes) when streaming the request body content from a ByteBufferChannel. Our use-case uses a ktor Netty server and Apache client to proxy the incoming request body out to a downstream service. We currently pass the ApplicationCall request content
channel directly to the ktor client request body using a ReadChannelContent
without any copying/joining of channels.
It appears that there might be a bug in ByteBufferChannel readAvailable(min: Int, block: (ByteBuffer) -> Unit): Int
which is used by ApacheRequestProduer
, where...
- Buffer arrives with content >= 4088 bytes
- writeFully writes 4088 bytes, flushes
- 4088 bytes
availableForRead
- writeFully suspends due to full channel
- ApacheRequestProduer attempts to read via
readAvailable
- 4088 bytes
availableForRead
;availableForRead
set to 0 - Apache encoder consumes zero bytes (unclear why, maybe just not ready?)
readAvailable
resumes the writeOp viabytesRead(state, 0)
- Useless flushing, can't write anything because it's still full
readAvailable
moves 4088 bytes back topendingToFlush
viastate.completeWrite(4088 - 0)
reading
block ends but capacity is never flushed again to move the 4088 bytes back toavailableForRead
ApacheRequestProducer
suspends waiting for content; writing coroutine (Netty) suspends waiting for the channel to be read
At this point, the coroutines are deadlocked but a manual flush should open it back up.
I'm not familiar enough with ByteBufferChannel
to open a PR with a fix but this single line change seems to mitigate the problem in my test environment: https://github.com/ktorio/ktor/compare/1.6.7...jhead:1.6.7-channel-fix?expand=1
This might impact other clients but last I checked, Apache was the only one I saw using this non-suspending readAvailable
API.
Version selector for API docs / Show stable API docs
Hi! Is there a way to see the API docs of the stable version of Ktor? https://api.ktor.io/ only shows me 2.0.0-beta-1 and I can't find a way to switch versions (e.g. to 1.6.7) in the docs.
Could not find ktor packages
I created a clean build of the Ktor server via a plugin for IDEA
My build.gradle.kts
val ktor_version: String by project
val kotlin_version: String by project
val logback_version: String by project
plugins {
application
kotlin("jvm") version "1.6.10"
}
group = "com.example"
version = "0.0.1"
application {
mainClass.set("io.ktor.server.netty.EngineMain")
}
repositories {
mavenCentral()
maven { url = uri("https://maven.pkg.jetbrains.space/public/p/ktor/eap") }
}
dependencies {
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-server-auth:$ktor_version")
implementation("io.ktor:ktor-server-sessions:$ktor_version")
implementation("io.ktor:ktor-server-auto-head-response:$ktor_version")
implementation("io.ktor:ktor-server-host-common:$ktor_version")
implementation("io.ktor:ktor-server-status-pages:$ktor_version")
implementation("io.ktor:ktor-server-caching-headers:$ktor_version")
implementation("io.ktor:ktor-server-compression:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-server-cors:$ktor_version")
implementation("io.ktor:ktor-server-default-headers:$ktor_version")
implementation("io.ktor:ktor-server-call-logging:$ktor_version")
implementation("io.ktor:ktor-server-freemarker:$ktor_version")
implementation("io.ktor:ktor-serialization-jackson:$ktor_version")
implementation("io.ktor:ktor-server-websockets:$ktor_version")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
testImplementation("io.ktor:ktor-server-tests:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}
My gradle.properties
ktor_version=1.6.7
kotlin_version=1.6.10
logback_version=1.2.3
kotlin.code.style=official
And my errors that I get when I try to run my new, clean project.
Execution failed for task ':compileKotlin'.
> Could not resolve all files for configuration ':compileClasspath'.
> Could not find io.ktor:ktor-server-auth:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-auth/1.6.7/ktor-server-auth-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-auth/1.6.7/ktor-server-auth-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-auto-head-response:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-auto-head-response/1.6.7/ktor-server-auto-head-response-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-auto-head-response/1.6.7/ktor-server-auto-head-response-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-status-pages:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-status-pages/1.6.7/ktor-server-status-pages-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-status-pages/1.6.7/ktor-server-status-pages-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-caching-headers:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-caching-headers/1.6.7/ktor-server-caching-headers-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-caching-headers/1.6.7/ktor-server-caching-headers-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-compression:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-compression/1.6.7/ktor-server-compression-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-compression/1.6.7/ktor-server-compression-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-content-negotiation:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-content-negotiation/1.6.7/ktor-server-content-negotiation-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-content-negotiation/1.6.7/ktor-server-content-negotiation-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-cors:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-cors/1.6.7/ktor-server-cors-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-cors/1.6.7/ktor-server-cors-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-default-headers:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-default-headers/1.6.7/ktor-server-default-headers-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-default-headers/1.6.7/ktor-server-default-headers-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-call-logging:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-call-logging/1.6.7/ktor-server-call-logging-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-call-logging/1.6.7/ktor-server-call-logging-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-freemarker:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-freemarker/1.6.7/ktor-server-freemarker-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-freemarker/1.6.7/ktor-server-freemarker-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-serialization-jackson:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-serialization-jackson/1.6.7/ktor-serialization-jackson-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-serialization-jackson/1.6.7/ktor-serialization-jackson-1.6.7.pom
Required by:
project :
> Could not find io.ktor:ktor-server-websockets:1.6.7.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/io/ktor/ktor-server-websockets/1.6.7/ktor-server-websockets-1.6.7.pom
- https://maven.pkg.jetbrains.space/public/p/ktor/eap/io/ktor/ktor-server-websockets/1.6.7/ktor-server-websockets-1.6.7.pom
Required by:
project :
Possible solution:
- Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html
And by the way, it doesn't matter if it's a new project or an old one, the errors are the same here and there.
I tried clearing the cache in IDEA, tried clearing the cache in gradle, tried changing the version of Ktor.
None of this helped me.
Any idea how to fix this?
Rewrite HtmlBuilder to New Plugins API
WebSocket memory leak
I managed to reproduce a memory leak involving WebSocket. Run it and you'll see that it consumes all available memory. In my system that happens within the first ten thousand iterations, even when it shouldn't.
import io.ktor.application.*
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.websocket.*
import io.ktor.http.*
import io.ktor.http.cio.websocket.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.websocket.*
import io.ktor.websocket.WebSockets
import kotlinx.coroutines.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
fun main() {
val server =
embeddedServer(Netty, port = 8080, host = "127.0.0.1") {
val serverId = AtomicInteger(1)
install(WebSockets)
routing {
webSocket("/echo") {
val i = serverId.getAndIncrement()
for (msg in incoming) {
when (msg) {
is Frame.Text -> {
val text = msg.readText().trim()
// println("[server $i] echo: $text")
send(Frame.Text(text))
}
else -> {
println("[server $i] received non-text message")
}
}
}
}
}
}
server.start()
runBlocking {
delay(500L)
val clientId = AtomicInteger(1)
repeat(1000000) {
val client = HttpClient(CIO) { install(io.ktor.client.features.websocket.WebSockets) }
client.webSocket(method = HttpMethod.Get, host = "127.0.0.1", port = 8080, path = "/echo") {
coroutineScope {
val i = clientId.getAndIncrement()
launch {
for (n in 1..3) {
val text = "number $n"
// println("[client $i] sending: $text")
send(Frame.Text(text))
}
}
repeat(3) {
when (val msg = incoming.receive()) {
is Frame.Text -> {
println("[client $i] received: ${msg.readText()}")
}
else -> {
println("[client $i] received non-text message")
}
}
}
println("[client $i] end processing")
}
}
}
}
server.stop(gracePeriod = 500L, timeout = 500L, timeUnit = TimeUnit.MILLISECONDS)
println("goodbye")
}
OAuth UserSession empty on Chrome but present on FireFox
I have a Ktor Back-End and react front-end both deployed and running in Heroku. I use Google OAuth for my authentication but on Chrome followup requests after the login have an empty UserSession causing a 401 response. On FireFox this works fine.
This is my code in my Application.kt file
@Suppress("unused") // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {
configureHTTP()
install(XForwardedHeaderSupport) //don't know if this helps but if I remove this line the server crashes when authenticating
val googleOauthProvider = OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = System.getenv("OAUTH_CLIENT_ID"),
clientSecret = System.getenv("OAUTH_SECRET"),
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile")
)
val httpClient = HttpClient(CIO) {
install(JsonFeature) {
serializer = KotlinxSerializer()
}
install (Logging)
}
install(Sessions) {
cookie<UserSession>("user_session") {
cookie.extensions["SameSite"] = "None"
cookie.secure = true
}
}
install(Authentication) {
oauth("auth-oauth-google") {
urlProvider = { System.getenv("OAUTH_CALLBACK_URL") }
providerLookup = { googleOauthProvider }
client = httpClient
}
}
install(Koin) {
modules(databaseModule)
}
configureRouting(httpClient)
configureSerialization()
configureMonitoring()
configureSecurity()
}
This is my code in the configureHttp method
fun Application.configureHTTP() {
install(CORS) {
method(HttpMethod.Options)
method(HttpMethod.Put)
method(HttpMethod.Delete)
method(HttpMethod.Patch)
header(HttpHeaders.Authorization)
header(HttpHeaders.ContentType)
allowNonSimpleContentTypes = true
allowCredentials = true
host("frontend-host", listOf("https")) //replaced for security
host("localhost:3000")
}
}
I'm very new to ktor and did not find anything in the documentation or on forums that could help me. So I created this issue hoping someone could help me out.
Thanks in advance!
Fix Plugin Button on the Last Page
Since the Ktor plugin is bundled, we shouldn't promote to install it and recommend using IDEA Ultimate instead
Pull Request - fix #1970 - update MultiPartFormDataContent to allow contentType override using optional builder
Pull Request - KTOR-1264 - Add UUID to DefaultConversionService
1.6.6
released 29th November 2021
Client
[iOS] Prevent HttpClient from persisting cookies across requests
Hello!
I'm using Ktor in a KMM app, and I am not having any kind of problem in Android, but in iOS it behaves weird. I don't have the HttpCookies plugin installed, because I'm handling and storing the session cookie outside of Ktor.
What happens is that the very first request that is sent to the server (GET /api/session
) contains a Set-Cookie
header in the response, and for this request I don't save the cookie nor do anything with it, the request serves only to check if there is a session based solely on the response of the server. Both in Android and iOS we get the Set-Cookie
header for this request.
The second request (POST /api/session
) is made after the user attempts to log in using their credentials. For this request, we need the response to contain the Set-Cookie
header so we can store the session token it contains and then pass it onto further requests. This happens in Android, but not in iOS. I tried removing the first request, and magically, I get a cookie for this one!
Is the iOS backend automatically storing and passing the cookie without my knowledge or consent? As I said before, I didn't install the HttpCookies plugin.
HttpCookies: parse / in the name of a cookie
I am receiving a cookie looking like that 384f8bdb/sessid=GLU787LwmQa9uLqnM7nWHzBm; path=/
.
Using the HttpCookies feature, i want ktor to send the 384f8bdb/sessid=GLU787LwmQa9uLqnM7nWHzBm
for all subsequent requests. Unfortunately, the cookie is parsed in a way that ignore everything after 384f8bdb
.
I've tracked down the issue to this point:
(commonMain/io/ktor/http/Cookie.kt)
@ThreadLocal
private val clientCookieHeaderPattern = """(^|;)\s*([^()<>@;:/\\"\[\]\?=\{\}\s]+)\s*(=\s*("[^"]*"|[^;]*))?""".toRegex()
When I check the regex against the cookie, it gives the following results:
Problem with that is, the cookie storage only save 384f8bdb=""
so the session id is never sent to the server in the following requests.
Is there any workaround for that (using the HttpCookies feature) ?
Is that the wanted behavior for ktor ?
Thanks
Cookies that added to request got removed if HttpCookies plugin is installed
To reproduce run the following test:
@Test
fun test() = runBlocking {
val client = HttpClient(MockEngine) {
engine {
addHandler { request ->
assertEquals("test=value", request.headers["Cookie"])
respond("")
}
}
install(HttpCookies) { // Without HttpCookies plugin the test passes
storage = AcceptAllCookiesStorage()
}
}
client.get<Unit>("/example") {
cookie("test", "value")
}
}
The 'refreshTokens' callback isn't invoked when an API returns a 401 response without the 'WWW-Authenticate' header
In the docs sample (https://ktor.io/docs/auth.html#bearer), the bearer
authentication is used to access the Google API. The problem is that the Google API doesn't return the WWW-Authenticate
with the 401
response when an access token is expired. This causes that the refreshTokens
callback isn't called and there is no way to refresh a token.
The log below doesn't have the WWW-Authenticate
header in a response:
11:33:50.424 [main] INFO io.ktor.client.HttpClient - REQUEST: https://www.googleapis.com/oauth2/v2/userinfo
11:33:50.424 [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
11:33:50.424 [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
11:33:50.425 [main] INFO io.ktor.client.HttpClient - -> Accept: application/json
11:33:50.425 [main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
11:33:50.425 [main] INFO io.ktor.client.HttpClient - -> Authorization: Bearer ya29.a0ARrdaM9sworHbT_H9DAQ3VKU9j_DvNdBvGBDBf_H87qioXt49-oZsE7c088qG4PIgBz4fCSrGGsJvMi0hsZO5FMjFpz2HjZ1wjufF7N47LLtQn6maZINLLlgWQ4CUgaRMxpIeb13byee9JqhtBUNPMfhcnYE
11:33:50.425 [main] INFO io.ktor.client.HttpClient - CONTENT HEADERS
11:33:50.425 [main] INFO io.ktor.client.HttpClient - -> Content-Length: 0
11:33:50.536 [main] INFO io.ktor.client.HttpClient - RESPONSE: 401 Unauthorized
11:33:50.536 [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=GET)
11:33:50.536 [main] INFO io.ktor.client.HttpClient - FROM: https://www.googleapis.com/oauth2/v2/userinfo
11:33:50.536 [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
11:33:50.536 [main] INFO io.ktor.client.HttpClient - -> Accept-Ranges: none
11:33:50.536 [main] INFO io.ktor.client.HttpClient - -> Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Cache-Control: no-cache, no-store, max-age=0, must-revalidate
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Content-Type: application/json; charset=UTF-8
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Date: Wed, 01 Dec 2021 08:33:50 GMT
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Expires: Mon, 01 Jan 1990 00:00:00 GMT
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Pragma: no-cache
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Server: ESF
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Transfer-Encoding: chunked
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> Vary: X-Origin; Referer; Origin,Accept-Encoding
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> X-Content-Type-Options: nosniff
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> X-Frame-Options: SAMEORIGIN
11:33:50.537 [main] INFO io.ktor.client.HttpClient - -> X-XSS-Protection: 0
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
401 Unauthorized
null
iOS: Failed to find HttpClientEngineContainer with new native memory model
When creating a Kotlin Multiplatform Mobile Library using Ktor, when creating a httpclient with an empty constructor(should use default httpclientengine), then the following exception is thrown:
kotlin.IllegalStateException: Failed to find HttpClientEngineContainer. Consider adding [HttpClientEngine] implementation in dependencies.[kotlin.Exception]
I have added the following to my build gradle:
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-ios:$ktor_version")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
}
}
val iosSimulatorArm64Main by getting
iosSimulatorArm64Main.dependsOn(iosMain)
val iosTest by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
}
}
val iosSimulatorArm64Test by getting
iosSimulatorArm64Test.dependsOn(iosTest)
Android behaves as expected but for some reason ktor is not using the default client engine.
Just for clarity, simply doing:
private val httpClientConfig: HttpClientConfig<*>.() -> Unit = {
install(JsonFeature) {
serializer = KotlinxSerializer()
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.ALL
}
}
HttpClient(httpClientConfig)
In the common layer, throws the exception, but i would expect it would use the default client engine for each of the platforms respectively.
HttpRequestRetry in KTOR 2.0 should allow for request altering between retries
Related to KTOR-572 by @rustam.siniukov ...
In site operations, it is useful when you have retries to be able to see retry traffic from the server viewpoint, as well as control retry decisions. This helps in cases where retry logic is causing storms of traffic across many clients even with falloff.
What is needed is the retry plugin to allow:
- when "deciding to retry or not", the lambda answering this questions requires visibility of the try count AND the request/response instances (i.e. response may have a header saying DON'T retry, or the opposite with a Retry-After header). Looking at count, headers, error code are all important.
- when "deciding the delay of the retry", the lambda answering this question needs the retry count AND the request/response instances since it might respect
Retry-After
style headers (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After). This applies to rate limiter headers (remaining, limit, reset, etc) as well. Alsox-no-retry
custom headers from the ops team blocking retries in an emergency at their edge firewall. Looking at count, headers, error code are all important. - before a retry the opportunity to modify the request object in needed based on the retry count and the request/response instances. This allows setting ops headers such as
x-retry-count: 5
which again allow edge control over retries. For example, in an outage recovery I might want to kill all retries with a count above 1, or any with a count at all to stop retries for a moment. The server needs to see evidence of the retry to do so, therefore modifying the headers is important.
The HttpRequestRetry
is useful but incomplete as it takes into account what the client wants, but not what a server/ops might want and to cooperate.
The request here is for the hooks for the events with the correct data, not implementing the specific examples given. They vary wildly other than Retry-After
which even browsers implement (https://stackoverflow.com/questions/3764075/retry-after-http-response-header-does-it-affect-anything).
Ability to modify request in client retries
It would be nice to be able to modify headers for instance between retry requests. Per customer feedback https://twitter.com/RevDocApatrida/status/1468176917513785346
ByteReadChannel.toByteArray() throws NoSuchMethodError after update to 1.6.6 version on Android client
After update ktor client from 1.6.4 to 1.6.6 below code throws exception on android 26 also that error is related to the JDK version because on android 31 you cannot reproduce it.
val content: ByteReadChannel = response.content
content.toByteArray()
StackTrace:
java.lang.NoSuchMethodError: No virtual method limit(I)Ljava/nio/ByteBuffer; in class Ljava/nio/ByteBuffer; or its super classes (declaration of 'java.nio.ByteBuffer' appears in /system/framework/core-oj.jar)
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231) at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAvailable(ByteBufferChannel.kt:3546)
at io.ktor.utils.io.ByteBufferChannel.write$suspendImpl(ByteBufferChannel.kt:1523)
at io.ktor.utils.io.ByteBufferChannel.write(Unknown Source:0)
at io.ktor.utils.io.ByteWriteChannel$DefaultImpls.write$default(ByteWriteChannel.kt:99)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invokeSuspend(OkHttpEngine.kt:163)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invoke(Unknown Source:8)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invoke(Unknown Source:4)
at io.ktor.utils.io.CoroutinesKt$launchChannel$job$1.invokeSuspend(Coroutines.kt:132) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
DigestAuth challenge response is missing the `algorithm` value
ktor-client-auth fail a Digest auth challenge (Using version 2.0.0-eap-275)
After investigation, I can say that this is not a bug per se as the RFC (https://datatracker.ietf.org/doc/html/rfc2617) say at section 3.2.1 that algorithm attribute is optional and `If this is not present it is assumed to be "MD5"`.
But some server implementation are buggy (JBoss management on JBoss EAP 7.1 to name one), and won't work without the algorithm attribute present in challenge response (Got a 401).
So I would like to see it added or an option to force it's presence.
Basic auth not sending second request
Code:
private val ktorHttpClient = HttpClient(OkHttp) {
install(Auth) {
basic {
credentials { BasicAuthCredentials(username = "[REDACTED]", password = "[REDACTED]") }
}
}
install(Logging) {
logger = object : Logger {
override fun log(message: String) {
Log.d("Logger Ktor =>", message)
}
}
level = LogLevel.ALL
}
}
private suspend fun login() {
val url = "https://api.backblazeb2.com/b2api/v2/b2_authorize_account"
val resp = ktorHttpClient.get<HttpResponse>(url)
Log.d("BACKBLAZE", resp.readText())
}
Log output:
D/Logger Ktor =>: REQUEST: https://api.backblazeb2.com/b2api/v2/b2_authorize_account
D/Logger Ktor =>: METHOD: HttpMethod(value=GET)
COMMON HEADERS
-> Accept: */*
D/Logger Ktor =>: -> Accept-Charset: UTF-8
CONTENT HEADERS
-> Content-Length: 0
BODY Content-Type: null
D/Logger Ktor =>: BODY START
D/Logger Ktor =>: BODY END
D/EGL_emulation: eglMakeCurrent: 0xe73848a0: ver 2 0 (tinfo 0xe7383440)
D/Logger Ktor =>: RESPONSE: 401
METHOD: HttpMethod(value=GET)
D/Logger Ktor =>: FROM: https://api.backblazeb2.com/b2api/v2/b2_authorize_account
COMMON HEADERS
D/Logger Ktor =>: -> cache-control: max-age=0, no-cache, no-store
-> connection: keep-alive
D/Logger Ktor =>: -> content-length: 64
-> content-type: application/json;charset=utf-8
-> date: Mon, 22 Nov 2021 18:21:26 GMT
D/Logger Ktor =>: -> keep-alive: timeout=5
-> www-authenticate: BASIC realm="authorize_account"
D/Logger Ktor =>: BODY Content-Type: application/json; charset=utf-8
D/Logger Ktor =>: BODY START
D/Logger Ktor =>: {
"code": "bad_auth_token",
"message": "",
"status": 401
}
D/Logger Ktor =>: BODY END
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-4
io.ktor.client.features.ClientRequestException: Client request(https://api.backblazeb2.com/b2api/v2/b2_authorize_account) invalid: 401 . Text: "{
"code": "bad_auth_token",
"message": "",
"status": 401
}"
From what I understand, upon receiving a 401, Ktor is supposed to send a second request with the Authorization
header. This is not happening. I have tried with expectSuccess = false
and it still doesn't happen. It does work with sendWithoutRequest { true }
.
Core
AttributeKey instance is identified by its identity instead of its name
In my project i need pass any attributes when intercept the call with an authorization, the attributes are put correctly in the call request but when get any attribute this generate a exception: java.lang.IllegalStateException: No instance for key AttributeKey: caller.id. But I print the list of AttributeKeys and the key is in the list: [AttributeKey: caller.siteId, AttributeKey: AuthContext, AttributeKey: SendPipelineExecutedAttributeKey, AttributeKey: EngineResponse, AttributeKey: caller.scopes, AttributeKey: caller.id, AttributeKey: client.id, AttributeKey: caller.status], I need help please.
Incompatible change from io.ktor:ktor-server-core:1.6.5 to 1.6.6
Hi Team!
Within your class: io.ktor.http.URLBuilder.kt you changed the signiture of Url from
public data class Url
To
public data class Url internal constructor
Which prevents the usage for us. We are using it like:
private fun sanitize(url: Url): Url {
return Url(
protocol = url.protocol,
host = url.host,
specifiedPort = url.specifiedPort,
encodedPath = url.encodedPath,
parameters = sanitizeParameters(url.parameters),
fragment = url.fragment,
user = url.user,
password = url.password,
trailingQuery = url.trailingQuery,
)
}
Can you provide a fixed version e.g. 1.6.7 ? This would be the best for all customers of your library.
or provide a fix. I guess it should work somehow with the URLBuilder, but the new ParameterBuilder makes the compiler unhappy.
Docs
Clarify "Creating HTTP APIs" documentation regarding testing approach
The documentation for "Creating HTTP APIs" for Ktor has a section on "Automated Testing". As a part of the testing approach, it is suggested that a "testing = true" parameter needs to be added to the Application.module() function. However, a reason is not given as to why this is necessary to do.
Based on my experience, making changes to production code for the sake if testability is a code smell and should be avoided. Therefore, I tried to remove this "testing" parameter and so far as I can tell. it appears that the test still functions as expected.
Searching for other documentation regarding testing Ktor, the "Testing Overview" section illustrates the most basic of testing approaches and it doesn't appear as if adding a "testing" parameter is necessary.
I would be happy to make a PR on this part of the documentation to clarify, however before doing so I thought it would be best to confirm with the team:
- Was there a reason for adding the "testing" parameter? Is the code still able to be properly tested without this parameter?
- Given my lack of knowledge around Ktor and testing Ktor, are the other considerations with regards to testing that need to be taken into consideration for the documentation?
If the above points can be clarified I'd be happy to make a PR for this. Thank you!
EAP 2.0 Documentation mention non existing method `sendWithoutRequest`
The sendWithoutRequest
method mentionned here https://ktor.io/docs/eap/auth.html#digest is not available
I don't know if you expect bug report about documentation about EAP, sorry if you know the doc is outdated and plan to update it later.
And if I work my way to enable it, their is an NPE. As a workaround, I did :
install(Auth) {
providers+=object:AuthProvider by DigestAuthProvider({DigestAuthCredentials("foo", "bar")}, "MyRealm"){
val notFirst= Collections.synchronizedSet(mutableSetOf<String>())
override fun sendWithoutRequest(request: HttpRequestBuilder): Boolean {
return !notFirst.add(request.url.host+":"+request.url.port)
}
}
If not used, EACH call start without auth header.... So each call make 2 request (first the 401, then the 200)
Also, the nc
attribute of the authorization header is incremented even when the challenge is reset.
Website docs issue with CORS hosts subdomain
Here: https://ktor.io/docs/cors.html#hosts
it gives "subDomains" as an example like so: subDomains = listOf("en,de,es")
but I'm pretty sure it should be subDomains = listOf("en", "de", "es")
IntelliJ IDEA Plugin
Ktor plugin in IDEA 2021.3 suggests migrating the 2.0.0-eap project to 1.6.6
- Run IDEA 2021.3.
- Open the https://github.com/ktorio/ktor-documentation/tree/main/codeSnippets project and switch to the 2.0.0 branch.
=> IDEA suggests migrating this project to 1.6.6.
P.S. Maybe it's related to absense of the 2.0.0-eap version in a plugin for IDEA 2021.3.
Server
Migrate plugins to new API
corsCheckRequestHeaders false
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/1722
Ktor Version and Engine Used (client or server and name)
ktor_version=1.3.1
server
Describe the bug
CORS feature installed in Application
install(CORS)
{
method(HttpMethod.Options)
header(HttpHeaders.XForwardedProto)
anyHost()
allowSameOrigin = false
allowCredentials = true
allowNonSimpleContentTypes = true
maxAgeDuration = 1.toDuration(DurationUnit.DAYS)
}
The preflight request of some browser contains Access-Control-Request-Headers, but the field-value of it is empty, function corsCheckRequestHeaders will return false, and the browser will get 403 status.
preflight request header
Host: xxx
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: https://xxx
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1295.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat
Access-Control-Request-Headers:
Accept: /
Referer: https://xxx
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.5;q=0.4
corsCheckRequestHeaders()
private fun ApplicationCall.corsCheckRequestHeaders(): Boolean {
val requestHeaders =
request.headers.getAll(HttpHeaders.AccessControlRequestHeaders)
?.filter { !it.isBlank() } // add this line to fix the issue <<<<<<<<<<<<<<<<<<<<<<<
?.flatMap { it.split(",") }
?.map {
it.trim().toLowerCasePreservingASCIIRules()
} ?: emptyList()
return requestHeaders.none { it !in allHeadersSet }
}
Session cookie with BASE64 encoding fails to set correct cookie
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/1447
Ktor Version and Engine Used (client or server and name)
1.2.5 and 1.3.0-beta-1, server, netty and CIO
Describe the bug
When using the base64 encoding for a session cookie, the correct cookie is not picked up.
In my repro example below I am basically calling /login
, which sets the session, and then /
, where the session is evaluated. When using base64 encoding, the second call doesn't succeed, as no session is found.
Important to notice that this works with all other encodings, and even with base64 in the test engine.
To Reproduce
Minimal repro here: https://github.com/AndreasVolkmann/ktor-session
Steps to reproduce the behavior:
- Start the server
- Go to
localhost:5000/login
which should returnLogged in
and set the session / cookie. - Go to
localhost:5000
where an error is shown
When changing the encoding, the above scenario works.
Expected behavior
The session cookie should be set and valid for the next call, just like with all other encodings and under test.
Tested with multiple browsers and postman.
Rewrite Netty Engine
Netty Engine flushing to the channel twice for every response now (for header and content). The flush
is an expensive operation and it's called for every response , so it makes Netty engine slow.
The solution is to make flush only when reading responses is completed (when user starts waiting for responses).
Rewrite includes ktor-server-netty
module.
Error with Koin DI in Ktor version 1.6.6+
When adding modules for dependency injection with Koin (using latest version 3.1.4) there is a weird bug in versions 1.6.6+
Here's my repo. This error can easily be mitigated by migrating down to Ktor version 1.6.5 and under, and only surfaces in 1.6.6 and higher.
Here's is a link to the branch where I added it and had to migrate my Ktor version down: https://github.com/JimmyMcBride/boruto-server/tree/19-create_all_heroes_endpoint_p1
Exception in thread "main" java.lang.NoSuchMethodError: 'double kotlin.time.Duration.toDouble-impl(long, java.util.concurrent.TimeUnit)'
at org.koin.core.time.MeasureKt.measureDuration(Measure.kt:32)
at org.koin.core.KoinApplication.modules(KoinApplication.kt:59)
at org.koin.core.KoinApplication.modules(KoinApplication.kt:42)
at com.example.plugins.KoinKt$configureKoin$1.invoke(Koin.kt:11)
at com.example.plugins.KoinKt$configureKoin$1.invoke(Koin.kt:9)
at org.koin.core.context.GlobalContext.startKoin(GlobalContext.kt:64)
at org.koin.core.context.DefaultContextExtKt.startKoin(DefaultContextExt.kt:31)
at org.koin.ktor.ext.Koin$Feature.install(KoinFeature.kt:48)
at org.koin.ktor.ext.Koin$Feature.install(KoinFeature.kt:42)
at io.ktor.application.ApplicationFeatureKt.install(ApplicationFeature.kt:68)
at com.example.plugins.KoinKt.configureKoin(Koin.kt:9)
at com.example.ApplicationKt.module(Application.kt:11)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Static.call(CallerImpl.kt:106)
at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:159)
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
at io.ktor.server.engine.internal.CallableUtilsKt.callFunctionWithInjection(CallableUtils.kt:119)
at io.ktor.server.engine.internal.CallableUtilsKt.executeModuleFunction(CallableUtils.kt:36)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$launchModuleByName$1.invoke(ApplicationEngineEnvironmentReloading.kt:332)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$launchModuleByName$1.invoke(ApplicationEngineEnvironmentReloading.kt:331)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.avoidingDoubleStartupFor(ApplicationEngineEnvironmentReloading.kt:356)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.launchModuleByName(ApplicationEngineEnvironmentReloading.kt:331)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.access$launchModuleByName(ApplicationEngineEnvironmentReloading.kt:30)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$instantiateAndConfigureApplication$1.invoke(ApplicationEngineEnvironmentReloading.kt:312)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading$instantiateAndConfigureApplication$1.invoke(ApplicationEngineEnvironmentReloading.kt:310)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.avoidingDoubleStartup(ApplicationEngineEnvironmentReloading.kt:338)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:310)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:143)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:277)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:174)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:26)
at com.example.ApplicationKt.main(Application.kt:7)
Process finished with exit code 1
Migrate plugins to multiplatform
Some Netty EngineMain properties are not set
Ktor Version
1.6.4
Ktor Engine Used
Netty Server
Behaviour
Only some of NettyApplicationEngine
's properties are loaded from ApplicationConfig
set when using EngineMain
.
Expected behaviour
After reading https://ktor.io/docs/engines.html#configure-engine I assumed it would be possible to configure all properties (besides the functions) via the configuration files.
Missing runningLimit
, requestReadTimeoutSeconds
and tcpKeepAlive
DropwizardMetrics does not append baseName to the 'per endpoint'-metrics breaking-change
When setting basename
install(DropwizardMetrics) {
registry = metricRegistry
baseName = "my.prefix"
}
metrics for endpoints does not get prefixed with the baseName I set.
When GET-ing /some/path/
I get metrics /some/path/(method:GET)
but I expect my.prefix./some/path/(method:GET)
I am using ktor 1.5.2
Development mode isn't taken into account for subroutes
To reproduce run the following code and make a GET / request:
fun main() {
val env = applicationEngineEnvironment {
developmentMode = true
connector {
port = 4444
}
module {
routing {
get("/") {
throw RuntimeException()
}
}
}
}
embeddedServer(Netty, env).start()
}
In the stack trace I observe a line: io.ktor.util.pipeline.SuspendFunctionGun.execute
. Since development mode is enabled I expect that only DebugPipelineContext
is used but for all routes, except for the Routing
, SuspendFunctionGun
is executed.
Test Infrastructure
Could not resolve org.jetbrains.kotlin:kotlin-test:1.6.0 when running ktor-client-mock tests
To reproduce run the :ktor-client:ktor-client-mock:compileTestKotlinJvm
Gradle task on the latest main
branch.
Execution failed for task ':ktor-client:ktor-client-mock:compileTestKotlinJvm'.
> Error while evaluating property 'filteredArgumentsMap' of task ':ktor-client:ktor-client-mock:compileTestKotlinJvm'
> Could not resolve all files for configuration ':ktor-client:ktor-client-mock:jvmTestCompileClasspath'.
> Could not resolve org.jetbrains.kotlin:kotlin-test:1.6.0.
Required by:
project :ktor-client:ktor-client-mock
> Unable to find a variant of org.jetbrains.kotlin:kotlin-test:1.6.0 providing the requested capability org.jetbrains.kotlin:kotlin-test-framework-junit:
- Variant compile provides org.jetbrains.kotlin:kotlin-test:1.6.0
- Variant runtime provides org.jetbrains.kotlin:kotlin-test:1.6.0
- Variant platform-compile provides org.jetbrains.kotlin:kotlin-test-derived-platform:1.6.0
- Variant platform-runtime provides org.jetbrains.kotlin:kotlin-test-derived-platform:1.6.0
- Variant enforced-platform-compile provides org.jetbrains.kotlin:kotlin-test-derived-enforced-platform:1.6.0
- Variant enforced-platform-runtime provides org.jetbrains.kotlin:kotlin-test-derived-enforced-platform:1.6.0
Other
"io.ktor.serializaion.gson" - package naming in 2.0
I see that the package name for some of the packages under serialization are named as "serializaion". This is one example. If this is intentional, please feel free to close the issue.
Thanks
Fix Log Size for Java 11 Windows Build
Development Mode introduces issues with Class Loader
When the application is run in development mode, the hibernate result class check fails with the following message:
Type specified for TypedQuery [com.x.Account] is incompatible with query return type [class com.x.Account]
This error does not occur when development mode is switched off.
Drop Old Patch Releases from API Docs to Reduce Space Consumption
We should drop everything before 1.6.6
createRoutingScopedPlugin does not call onCallReceive in v2.0.0
createRoutingScopedPlugin does not call onCallReceive in v2.0.0
WebSocketSession improvement
hi
- just i hope to add details (host, dns, userAgent, ....) about who connet to ktor websocker server
- register all users connection automaticaly and offre a way to replay message to all user connected
- add exception handler to WebSocketSession like awaitSessionException(ex: (Throwble) -> Unit)
NoSuchMethod error when using JDK 8
Caused by: java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231)
at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAvailable(ByteBufferChannel.kt:3506)
at io.ktor.utils.io.ByteBufferChannel.write$suspendImpl(ByteBufferChannel.kt:1523)
at io.ktor.utils.io.ByteBufferChannel.write(ByteBufferChannel.kt)
at io.ktor.utils.io.ByteWriteChannel$DefaultImpls.write$default(ByteWriteChannel.kt:99)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invokeSuspend(OkHttpEngine.kt:163)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invoke(OkHttpEngine.kt)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invoke(OkHttpEngine.kt)
at io.ktor.utils.io.CoroutinesKt$launchChannel$job$1.invokeSuspend(Coroutines.kt:132)
As you can see it is obviously the fact that JDK < 9. Is JDK 8 supported?
Ktor 2.0.0 EAP-256 reports java.lang.NoSuchMethodError under JVM 1.8 environment.
Hi,
Our program runs in the JVM 1.8 environment. After upgrading to ktor 2.0.0 EAP-256, the following error will be reported when running:
java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:211)
at io.ktor.utils.io.ByteBufferChannel.setupStateForRead(ByteBufferChannel.kt:303)
at io.ktor.utils.io.ByteBufferChannel.access$setupStateForRead(ByteBufferChannel.kt:24)
at io.ktor.utils.io.ByteBufferChannel.readAsMuchAsPossible(ByteBufferChannel.kt:2436)
at io.ktor.utils.io.ByteBufferChannel.readAsMuchAsPossible$default(ByteBufferChannel.kt:493)
at io.ktor.utils.io.ByteBufferChannel.remainingPacket(ByteBufferChannel.kt:2085)
at io.ktor.utils.io.ByteBufferChannel.readRemaining$suspendImpl(ByteBufferChannel.kt:2073)
at io.ktor.utils.io.ByteBufferChannel.readRemaining(ByteBufferChannel.kt)
at io.ktor.utils.io.ByteReadChannelKt.readRemaining(ByteReadChannel.kt:208)
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:79)
at io.ktor.client.plugins.ContentNegotiation$Plugin$install$2.invokeSuspend(ContentNegotiation.kt:124)
at io.ktor.client.plugins.ContentNegotiation$Plugin$install$2.invoke(ContentNegotiation.kt)
at io.ktor.client.plugins.ContentNegotiation$Plugin$install$2.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:127)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:85)
at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:176)
at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:127)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:85)
at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:95)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:126)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(HttpCallValidator.kt)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(HttpCallValidator.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:127)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:85)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:105)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:82)
at io.ktor.client.call.HttpClientCall.body(HttpClientCall.kt:98)
at com.netviewtech.sdk.http.plugins.intercept.NetvueHttpIntercept$Plugin$install$2.invokeSuspend(NetvueHttpIntercept.kt:112)
(Coroutine boundary)
at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:176)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:126)
at io.ktor.client.call.HttpClientCall.body(HttpClientCall.kt:98)
at com.netviewtech.sdk.http.plugins.intercept.NetvueHttpIntercept$Plugin$install$2.invokeSuspend(NetvueHttpIntercept.kt:112)
at io.ktor.client.plugins.HttpRedirect$Plugin$install$1.invokeSuspend(HttpRedirect.kt:60)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$3.invokeSuspend(HttpCallValidator.kt:135)
at io.ktor.client.plugins.HttpSend$Plugin$install$1.invokeSuspend(HttpSend.kt:95)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:114)
at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:37)
at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:192)
at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:104)
at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:46)
at com.netviewtech.sdk.http.plugins.NetvueHttpInterceptTests$testSkewTime$1.invokeSuspend(NetvueHttpInterceptTests.kt:128)
at com.netviewtech.sdk.test.coroutine.BlockingTestAndroidKt$blockingTest$1$1.invokeSuspend(BlockingTestAndroid.kt:22)
at com.netviewtech.sdk.test.coroutine.BlockingTestAndroidKt$blockingTest$1.invokeSuspend(BlockingTestAndroid.kt:21)
It may be similar to this issue.
URL port should be in 0..65535
Update Kotlin to 1.6.0
1.6.5
released 2nd November 2021
Client
Ktor IOS client sometimes deadlocks if Logging is installed
If the Logging plugin is installed the Ktor client deadlocks/blocks sometimes after BODY START
is printed to the console.
The response is still getting returned back to the calling function, but any future requests will block.
It doesn't happen every time, but it is reasonably easy to reproduce it with the attached Sample app.
KMM - IOS HTTP Request blocks during image download
When the HttpClient has LogLevel.ALL or LogLevel.BODY sometimes the logs stop and nothing happens after, everything work fine in Android.
Class in shared files:
import io.ktor.client.*
import io.ktor.client.features.*
import io.ktor.client.features.logging.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.utils.io.*
import kotlinx.serialization.json.Json
class ApiBridge {
companion object {
private val client by lazy { createHttpClient(true) }
suspend fun fetchImageData(
listimage: List<ListImage>,
) {
listimage.forEachIndexed { index, it ->
it.apply {
downloadFile(urlString)
}
}
return
}
suspend fun downloadFile(url: String) = apiRequest<HttpResponse>(HttpMethod.Get, url)
private suspend inline fun <reified T> apiRequest(
httpMethod: HttpMethod,
urlString: String,
): T? = try {
client.request<T> {
method = httpMethod
url(urlString)
}
} catch (t: Throwable) {
val content = (t as ResponseException).response.content.readUTF8Line()
content?.let {
val element = Json.parseToJsonElement(it)
}
null
}
}
}
private fun createHttpClient(enableNetworkLogs: Boolean) = HttpClient {
if (enableNetworkLogs) {
install(Logging) {
logger = Logger.SIMPLE
level = LogLevel.ALL
}
}
}
data class ListImage(
val urlString: String,
var photoLocalUri: String
)
IOS:
import SwiftUI
import shared
struct ContentView: View {
var listimage: [ListImage] = [
ListImage(urlString: "https://www.google.com/chrome/static/images/intl/fr_FR/download-browser/big_pixel_phone.png", photoLocalUri: ""),
ListImage(urlString: "https://miro.medium.com/max/1200/1*3XpF4zrIIIZKonQC7uRHAg.jpeg", photoLocalUri: ""),
ListImage(urlString: "https://blog.jetbrains.com/wp-content/uploads/2021/08/KMM-release-scheme_Blogpost.jpg", photoLocalUri: "")
]
var body: some View {
Button(action: {
print("Start\n")
ApiBridge.Companion().fetchImageData(listimage: listimage, completionHandler: {_,_ in
print("End\n----------------------\n")
})
}) {
Text("Download Image")
}
}
}
Log:
Start
HttpClient: REQUEST: https://www.google.com/chrome/static/images/intl/fr_FR/download-browser/big_pixel_phone.png
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 0
HttpClient: BODY Content-Type: null
HttpClient: BODY START
HttpClient:
HttpClient: BODY END
2021-11-08 11:34:53.398369+0100 iosApp[1627:202009] [connection] nw_endpoint_handler_set_adaptive_read_handler [C22.1 216.58.213.68:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for read_timeout failed
2021-11-08 11:34:53.398490+0100 iosApp[1627:202009] [connection] nw_endpoint_handler_set_adaptive_write_handler [C22.1 216.58.213.68:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for write_timeout failed
HttpClient: RESPONSE: 200 OK
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: FROM: https://www.google.com/chrome/static/images/intl/fr_FR/download-browser/big_pixel_phone.png
HttpClient: COMMON HEADERS
HttpClient: -> Accept-Ranges: bytes
HttpClient: -> Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
HttpClient: -> Cache-Control: private, max-age=31536000
HttpClient: -> Content-Length: 28839
HttpClient: -> Content-Type: image/png
HttpClient: -> Date: Mon, 08 Nov 2021 10:34:53 GMT
HttpClient: -> Expires: Mon, 08 Nov 2021 10:34:53 GMT
HttpClient: -> Last-Modified: Thu, 23 Sep 2021 20:30:00 GMT
HttpClient: -> Server: sffe
HttpClient: -> content-security-policy-report-only: require-trusted-types-for 'script'; report-uri https://csp.withgoogle.com/csp/uxe-owners-acl/chrome
HttpClient: -> cross-origin-opener-policy-report-only: same-origin; report-to="uxe-owners-acl/chrome"
HttpClient: -> cross-origin-resource-policy: cross-origin
HttpClient: -> report-to: {"group":"uxe-owners-acl/chrome","max_age":2592000,"endpoints":[{"url":"https://csp.withgoogle.com/csp/report-to/uxe-owners-acl/chrome"}]}
HttpClient: -> x-content-type-options: nosniff
HttpClient: -> x-xss-protection: 0
HttpClient: BODY Content-Type: image/png
HttpClient: BODY START
HttpClient: [response body omitted]
HttpClient: BODY END
HttpClient: REQUEST: https://miro.medium.com/max/1200/1*3XpF4zrIIIZKonQC7uRHAg.jpeg
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 0
HttpClient: BODY Content-Type: null
HttpClient: BODY START
HttpClient:
HttpClient: BODY END
2021-11-08 11:34:53.511332+0100 iosApp[1627:202014] [connection] nw_endpoint_handler_set_adaptive_read_handler [C23.1 162.159.153.4:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for read_timeout failed
2021-11-08 11:34:53.511447+0100 iosApp[1627:202014] [connection] nw_endpoint_handler_set_adaptive_write_handler [C23.1 162.159.153.4:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for write_timeout failed
HttpClient: RESPONSE: 200 OK
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: FROM: https://miro.medium.com/max/1200/1*3XpF4zrIIIZKonQC7uRHAg.jpeg
HttpClient: COMMON HEADERS
HttpClient: -> Accept-Ranges: bytes
HttpClient: -> Access-Control-Allow-Origin: *
HttpClient: -> Age: 11
HttpClient: -> Alt-Svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400, h3-28=":443"; ma=86400, h3-27=":443"; ma=86400
HttpClient: -> Cache-Control: public, max-age=2592000
HttpClient: -> Content-Length: 42538
HttpClient: -> Content-Type: image/jpeg
HttpClient: -> Date: Mon, 08 Nov 2021 10:34:53 GMT
HttpClient: -> Etag: "16.3"
HttpClient: -> Expires: Wed, 08 Dec 2021 10:34:53 GMT
HttpClient: -> Pragma: public
HttpClient: -> Server: cloudflare
HttpClient: -> Strict-Transport-Security: max-age=15552000; includeSubDomains; preload
HttpClient: -> Vary: Accept-Encoding
HttpClient: -> cf-bgj: h2pri
HttpClient: -> cf-cache-status: HIT
HttpClient: -> cf-ray: 6aae26c50f147339-MRS
HttpClient: -> expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
HttpClient: -> medium-fulfilled-by: miro/main-20211018-134342-44be7a075d
HttpClient: -> sepia-upstream: medium
HttpClient: -> x-content-type-options: nosniff
HttpClient: -> x-envoy-upstream-service-time: 47
HttpClient: BODY Content-Type: image/jpeg
HttpClient: BODY START
HttpClient: [response body omitted]
HttpClient: BODY END
Fix `testErrorHandling` with JS
testErrorHandling
fails on JS with assertFailsWith
.
JS client seem to ignore `HttpCookies` feature (or header more generally) in browser target, but not in nodejs one
My Ktor JS client is not receiving proper headers in browser target, despite it being working in nodejs target.
I reproduced the issue using a simple Ktor server:
data class UserSession(val id: String, val count: Int)
fun main() {
embeddedServer(Jetty, port = 9000, host = "0.0.0.0") {
install(CORS) {
anyHost()
}
install(Sessions) {
cookie<UserSession>("user_session")
}
routing {
post("/login") {
val name = call.receive(String::class)
call.sessions.set(UserSession(id = name, count = 0))
call.respond(HttpStatusCode.NoContent)
}
get("/session") {
val userSession = call.sessions.get<UserSession>() ?: error("no session")
call.respond(userSession.id)
}
}
}.start(wait = true)
}
On the client side, my client build.gradle.kts
looks like:
kotlin {
jvm()
js(IR) {
browser()
nodejs()
}
// ...
}
Consider this test:
@Test
fun shouldLogin() = runTest {
val client = HttpClient(Js) {
install(HttpCookies)
install(Logging)
}
val name = "test"
client.post<String>("http://0.0.0.0:9000/login") { body = name }
val username = client.get<String>("http://0.0.0.0:9000/session")
assertEquals(name, username)
}
I observed the following:
Target | Test passing? |
---|---|
NodeJS | Yes |
Browser/ChromeHeadless96.0.4664.110,MacOS10.15.7 | No |
Browser/Firefox95.0,MacOS10.15 | No |
Logs from "js, node" test run:
HttpClient: REQUEST: http://0.0.0.0:9000/login
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 4
HttpClient: -> Content-Type: text/plain; charset=UTF-8
HttpClient: RESPONSE: 204 No Content
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: FROM: http://0.0.0.0:9000/login
HttpClient: COMMON HEADERS
HttpClient: -> connection: close
HttpClient: -> set-cookie: user_session=count%3D%2523i0%26id%3D%2523stest; Max-Age=604800; Expires=Sun, 09 Jan 2022 10:38:42 GMT; Path=/; HttpOnly; $x-enc=URI_ENCODING
HttpClient: REQUEST: http://0.0.0.0:9000/session
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: -> Cookie: user_session=count%3D%2523i0%26id%3D%2523stest
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 0
HttpClient: RESPONSE: 200 OK
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: FROM: http://0.0.0.0:9000/session
HttpClient: COMMON HEADERS
HttpClient: -> connection: close
HttpClient: -> content-length: 4
HttpClient: -> content-type: text/plain;charset=utf-8
HttpClient: -> set-cookie: user_session=count%3D%2523i0%26id%3D%2523stest; Max-Age=604800; Expires=Sun, 09 Jan 2022 10:38:42 GMT; Path=/; HttpOnly; $x-enc=URI_ENCODING
Logs from "js, browser, ChromeHeadless96.0.4664.110,MacOS10.15.7" test run:
HttpClient: REQUEST: http://127.0.0.1:9000/login
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 4
HttpClient: -> Content-Type: text/plain; charset=UTF-8
HttpClient: RESPONSE: 204 No Content
HttpClient: METHOD: HttpMethod(value=POST)
HttpClient: FROM: http://127.0.0.1:9000/login
HttpClient: COMMON HEADERS
HttpClient: REQUEST: http://127.0.0.1:9000/session
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: COMMON HEADERS
HttpClient: -> Accept: */*
HttpClient: -> Accept-Charset: UTF-8
HttpClient: CONTENT HEADERS
HttpClient: -> Content-Length: 0
HttpClient: RESPONSE: 401 Unauthorized
HttpClient: METHOD: HttpMethod(value=GET)
HttpClient: FROM: http://127.0.0.1:9000/session
HttpClient: COMMON HEADERS
HttpClient: -> content-length: 0
It looks like common headers are absent, especially the crucial cookie related ones.
I do not know if it is a bug, or if I misconfigured something, any idea?
EDIT: I changed the issue from Multiplatform, to JS only as this is reproducible even using only the JS engine in two different targets.
ByteReadChannel.toByteArray() throws NoSuchMethodError after update to 1.6.6 version on Android client
After update ktor client from 1.6.4 to 1.6.6 below code throws exception on android 26 also that error is related to the JDK version because on android 31 you cannot reproduce it.
val content: ByteReadChannel = response.content
content.toByteArray()
StackTrace:
java.lang.NoSuchMethodError: No virtual method limit(I)Ljava/nio/ByteBuffer; in class Ljava/nio/ByteBuffer; or its super classes (declaration of 'java.nio.ByteBuffer' appears in /system/framework/core-oj.jar)
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231) at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAvailable(ByteBufferChannel.kt:3546)
at io.ktor.utils.io.ByteBufferChannel.write$suspendImpl(ByteBufferChannel.kt:1523)
at io.ktor.utils.io.ByteBufferChannel.write(Unknown Source:0)
at io.ktor.utils.io.ByteWriteChannel$DefaultImpls.write$default(ByteWriteChannel.kt:99)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invokeSuspend(OkHttpEngine.kt:163)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invoke(Unknown Source:8)
at io.ktor.client.engine.okhttp.OkHttpEngineKt$toChannel$1.invoke(Unknown Source:4)
at io.ktor.utils.io.CoroutinesKt$launchChannel$job$1.invokeSuspend(Coroutines.kt:132) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Basic auth not sending second request
Code:
private val ktorHttpClient = HttpClient(OkHttp) {
install(Auth) {
basic {
credentials { BasicAuthCredentials(username = "[REDACTED]", password = "[REDACTED]") }
}
}
install(Logging) {
logger = object : Logger {
override fun log(message: String) {
Log.d("Logger Ktor =>", message)
}
}
level = LogLevel.ALL
}
}
private suspend fun login() {
val url = "https://api.backblazeb2.com/b2api/v2/b2_authorize_account"
val resp = ktorHttpClient.get<HttpResponse>(url)
Log.d("BACKBLAZE", resp.readText())
}
Log output:
D/Logger Ktor =>: REQUEST: https://api.backblazeb2.com/b2api/v2/b2_authorize_account
D/Logger Ktor =>: METHOD: HttpMethod(value=GET)
COMMON HEADERS
-> Accept: */*
D/Logger Ktor =>: -> Accept-Charset: UTF-8
CONTENT HEADERS
-> Content-Length: 0
BODY Content-Type: null
D/Logger Ktor =>: BODY START
D/Logger Ktor =>: BODY END
D/EGL_emulation: eglMakeCurrent: 0xe73848a0: ver 2 0 (tinfo 0xe7383440)
D/Logger Ktor =>: RESPONSE: 401
METHOD: HttpMethod(value=GET)
D/Logger Ktor =>: FROM: https://api.backblazeb2.com/b2api/v2/b2_authorize_account
COMMON HEADERS
D/Logger Ktor =>: -> cache-control: max-age=0, no-cache, no-store
-> connection: keep-alive
D/Logger Ktor =>: -> content-length: 64
-> content-type: application/json;charset=utf-8
-> date: Mon, 22 Nov 2021 18:21:26 GMT
D/Logger Ktor =>: -> keep-alive: timeout=5
-> www-authenticate: BASIC realm="authorize_account"
D/Logger Ktor =>: BODY Content-Type: application/json; charset=utf-8
D/Logger Ktor =>: BODY START
D/Logger Ktor =>: {
"code": "bad_auth_token",
"message": "",
"status": 401
}
D/Logger Ktor =>: BODY END
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-4
io.ktor.client.features.ClientRequestException: Client request(https://api.backblazeb2.com/b2api/v2/b2_authorize_account) invalid: 401 . Text: "{
"code": "bad_auth_token",
"message": "",
"status": 401
}"
From what I understand, upon receiving a 401, Ktor is supposed to send a second request with the Authorization
header. This is not happening. I have tried with expectSuccess = false
and it still doesn't happen. It does work with sendWithoutRequest { true }
.
Rename the 'Ios' client engine to more generic term to cover all Apple operating systems
The Ios
engine uses NSURLSession from the Foundation framework, which can be used not only for iOS but for other operating systems, including macOS, tvOS, etc. This leads to confusion that the Ios
engine can be used for iOS devices only. So it makes sense to rename the engine and artifacts to something more general, for example, Darwin or smth else.
JS Client doesn't support ServiceWorker
Can't send request from ServiceWorker, it fails with `require is not defined`
ServiceWorker scope doesn't have the window object.
This is a suggestion for service worker support: https://github.com/ktorio/ktor/pull/2696
OkHttpClient "Socket is closed"
Hello.
We are using Ktor in a KMM project with OKHttpEngine on Android side. Sometimes, on Android side, when sending a get request, the client throws an exception
SocketException("Socket is closed")
After a long research of Ktor source code, I came to the conclusion that the HTTP request is being processed successfully, an error occurs at the time of reading the request data.
private suspend fun executeHttpRequest(
engine: OkHttpClient,
engineRequest: Request,
callContext: CoroutineContext,
requestData: HttpRequestData
): HttpResponseData {
val requestTime = GMTDate()
val response = engine.execute(engineRequest, requestData)
val body = response.body
callContext[Job]!!.invokeOnCompletion { body?.close() }
val responseContent = body?.source()?.toChannel(callContext, requestData) ?: ByteReadChannel.Empty
return buildResponseData(response, requestTime, responseContent, callContext)
}
private fun BufferedSource.toChannel(context: CoroutineContext, requestData: HttpRequestData): ByteReadChannel =
GlobalScope.writer(context) {
use { source ->
var lastRead = 0
while (source.isOpen && context.isActive && lastRead >= 0) {
channel.write { buffer ->
lastRead = try {
source.read(buffer)
} catch (cause: Throwable) {
throw mapExceptions(cause, requestData)
}
}
}
}
}.channel
I suppose that
body?.close()
happens before the data is read into the channel
body?.source()?.toChannel(callContext, requestData) ?: ByteReadChannel.Empty
Coroutines version: 1.5.2-native-mt
KotlinVersion: 1.5.31
Client error handling policy
Hi!
Is there a recommended way to handle request errors? There is no mention of errors in client part of https://ktor.io/docs. And in HttpClient.request
javadoc there is only minimalistic sentence if fails, an exception is thrown
.
We'd like to handle "expected" (IO, bizzare server responses) exceptions and do not handle "unexpected" (programmer errors of any kind in custom features/ktor codebase/3rd party engines, JVM/OS-layer errors).
For some time we lived with the following code:
try {
httpClient.request { ... }
} catch (e: ResponseException) { ... }
} catch (e: IOException) { ... }
} catch (e: SerializationException) { ... }
and it was fine. But then we found out that NoTransformationFoundException
is also possible when server responded with unexpected content-type. Also, in K/N IllegalStateException and MalformedInputException may be thrown. And MalformedInputException
does not inherit from Exception
(is it a bug, btw? similar jvm exception inherit from IOException). So only catch (Throwable)
gives us request that could not lead to application crash.
Ktor adds a special value to Special symbols which are part of cookie
I am using Ktor as common library for platforms iOS and Android
our backend services are session and cookie based, where I first do authorization call, as response I get token, using that token as cookie header I need to make next consecutive requests for which ktor client is adding encoded value instead of actually passed value for which my backend is not providing valid response, can anyone help me in resolving this, upon verifying using proxy tools, if my backend is expecting AIKOXEyRBSpW8noxNxP0NA..|1636357088|huYnaZ7kpyR5OZ15Svvy5GWoEFg.ktor is passing
AIKOXEyRBSpW8noxNxP0NA%2E%2E%7C1636357088%7ChuYnaZ7kpyR5OZ15Svvy5GWoEFg%2E
Basically its adding different value for special symbols
My code used is as shown below
suspend fun getVersion(token: String): VersionResponse? {
return try {
val response: VersionResponse? = client.get {
url("https://cloudiq.emc.com/api/version")
val session = "ngssosession=$token"
println("fafa session - $session")
headers {
append("content-type", "application/json; charset=UTF-8")
append("Accept", "application/json")
append("Accept-Charset", "UTF-8")
append("accept-encoding", "deflate, gzip, br, zstd")
}
cookie("ngssosession", token)
}
response
} catch (exception: Exception) {
exception.printStackTrace()
null
}
}
Fix Flaky Timeout Priority Test
Core
Add Support for Apple Silicon Targets
Im trying to run the wizard project for KMP with Kotlin 1.5.30 on a M1 mac
I added this on my gradle
val iosTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = when {
System.getenv("SDK_NAME")?.startsWith("iphoneos") == true -> ::iosArm64
System.getenv("NATIVE_ARCH")?.startsWith("arm") == true -> ::iosSimulatorArm64
else -> ::iosX64
}
iosTarget("ios") {
binaries {
framework {
baseName = "shared"
}
}
}
I could run the app on android and iOS, but then I added the Ktor dependencies and getting getting the following issue when I trying to run the app on an iOS simulator
Could not resolve all files for configuration ':shared:iosCompileKlibraries'.
> Could not resolve io.ktor:ktor-client-core:1.6.2.
Required by:
project :shared
> No matching variant of io.ktor:ktor-client-core:1.6.2 was found. The consumer was configured to find a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native', attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64' but:
- Variant 'commonMainMetadataElements' capability io.ktor:ktor-client-core:1.6.2 declares a usage of 'kotlin-api' of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'common' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_simulator_arm64')
- Variant 'iosArm32ApiElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native':
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_arm32' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64'
- Variant 'iosArm32MetadataElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native':
- Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_arm32' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64'
- Variant 'iosArm64ApiElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native':
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_arm64' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64'
- Variant 'iosArm64MetadataElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native':
- Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_arm64' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64'
- Variant 'iosX64ApiElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native':
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_x64' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64'
- Variant 'iosX64MetadataElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native':
- Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_x64' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.native.target' with value 'ios_simulator_arm64'
- Variant 'jsIrApiElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a usage of 'kotlin-api' of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'js' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_simulator_arm64')
- Variant 'jsIrRuntimeElements-published' capability io.ktor:ktor-client-core:1.6.2:
- Incompatible because this component declares a usage of 'kotlin-runtime' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'js' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_simulator_arm64')
- Variant 'jsLegacyApiElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a usage of 'kotlin-api' of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'js' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_simulator_arm64')
- Variant 'jsLegacyRuntimeElements-published' capability io.ktor:ktor-client-core:1.6.2:
- Incompatible because this component declares a usage of 'kotlin-runtime' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'js' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_simulator_arm64')
- Variant 'jvmApiElements-published' capability io.ktor:ktor-client-core:1.6.2 declares an API of a component:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attribute:
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_simulator_arm64')
- Variant 'jvmRuntimeElements-published' capability io.ktor:ktor-client-core:1.6.2 declares a runtime of a component:
JDK8 throw an exception: java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
I use Gradle to compile the code on the jdk16 platform, and use following code to specify the jdk version, but an exception is thrown when running on JDK8.
Is ktor compatible with jdk8?
withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjsr305=strict", "-Xjvm-default=all")
}
}
withType<JavaCompile> {
with(options) {
encoding = Charsets.UTF_8.name()
isFork = true
isIncremental = true
release.set(8)
}
}
Exception:
2021-11-08 21:33:52.788 [eventLoopGroupProxy-4-6] ERROR Application - 200 OK: POST - /api/mask
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231)
at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAsMuchAsPossible(ByteBufferChannel.kt:3448)
at io.ktor.utils.io.ByteBufferChannel.writeFully$suspendImpl(ByteBufferChannel.kt:1094)
at io.ktor.utils.io.ByteBufferChannel.writeFully(ByteBufferChannel.kt)
at io.ktor.server.netty.cio.RequestBodyHandler.copy(RequestBodyHandler.kt:153)
at io.ktor.server.netty.cio.RequestBodyHandler.processContent(RequestBodyHandler.kt:110)
at io.ktor.server.netty.cio.RequestBodyHandler.access$processContent(RequestBodyHandler.kt:17)
at io.ktor.server.netty.cio.RequestBodyHandler$job$1.invokeSuspend(RequestBodyHandler.kt:42)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda-1$lambda-0(NettyApplicationEngine.kt:251)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
NoSuchMethodError on static
Kotlin 1.5.31
I am using static roting for folder. On JVM 11 it works properly, but when I am trying to retrieve static data with server on JVM 8, I am getting that stacktrace (pastebin) on the server side and Empty response
on the client side (browser)
ktor 1.6.5 caused: Caused by: java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
I get this stacktrace when using Apache, problem happens when switching from 1.6.4 to 1.6.5.
I am using the latest Java 8 JDK, am I forced to switch to more modern JDK?
SEVERE: I/O reactor terminated abnormally
org.apache.http.nio.reactor.IOReactorException: I/O dispatch worker terminated abnormally
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:359)
at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:221)
at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
Fail to deserialize Http POST request's body with the latest version 1.6.5
Version
Ktor version: 1.6.5
Kotlin version: 1.5.31
JVM version: 1.8 (1.8.0_171)
Bug description
when handle Http POST request, Ktor cannot read body content correctly and throw an exception with
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
With Ktor older version from 1.6.0 to 1.6.4, it works fine. im Curious whats changed in latest 1.6.5.
Here's the information may be useful.
Exception Whole Content
2021-11-05 17:02:06.106 [eventLoopGroupProxy-4-1] ERROR ktor.application - Unhandled: POST - /post
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at io.ktor.utils.io.ExceptionUtilsJvmKt$createConstructor$$inlined$safeCtor$3.invoke(ExceptionUtilsJvm.kt:103)
at io.ktor.utils.io.ExceptionUtilsJvmKt$createConstructor$$inlined$safeCtor$3.invoke(ExceptionUtilsJvm.kt:90)
at io.ktor.utils.io.ExceptionUtilsJvmKt.tryCopyException(ExceptionUtilsJvm.kt:66)
at io.ktor.utils.io.ByteBufferChannelKt.rethrowClosed(ByteBufferChannel.kt:2456)
at io.ktor.utils.io.ByteBufferChannelKt.access$rethrowClosed(ByteBufferChannel.kt:1)
at io.ktor.utils.io.ByteBufferChannel.setupStateForRead(ByteBufferChannel.kt:313)
at io.ktor.utils.io.ByteBufferChannel.access$setupStateForRead(ByteBufferChannel.kt:24)
at io.ktor.utils.io.ByteBufferChannel.readAsMuchAsPossible(ByteBufferChannel.kt:2510)
at io.ktor.utils.io.ByteBufferChannel.readAvailable$suspendImpl(ByteBufferChannel.kt:684)
at io.ktor.utils.io.ByteBufferChannel.readAvailable(ByteBufferChannel.kt)
at io.ktor.utils.io.jvm.javaio.InputAdapter$loop$1.loop(Blocking.kt:40)
at io.ktor.utils.io.jvm.javaio.InputAdapter$loop$1$loop$1.invokeSuspend(Blocking.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at io.ktor.utils.io.jvm.javaio.UnsafeBlockingTrampoline.dispatch(Blocking.kt:296)
at kotlinx.coroutines.internal.DispatchedContinuation.resumeWith(DispatchedContinuation.kt:201)
at io.ktor.utils.io.jvm.javaio.BlockingAdapter.submitAndAwait(Blocking.kt:233)
at io.ktor.utils.io.jvm.javaio.BlockingAdapter.submitAndAwait(Blocking.kt:206)
at io.ktor.utils.io.jvm.javaio.InputAdapter.read(Blocking.kt:67)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._loadMore(ReaderBasedJsonParser.java:276)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipWSOrEnd(ReaderBasedJsonParser.java:2443)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:698)
at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4762)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4668)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3643)
at io.ktor.jackson.JacksonConverter$convertForReceive$2.invokeSuspend(JacksonConverter.kt:65)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Caused by: java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231)
at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAsMuchAsPossible(ByteBufferChannel.kt:3448)
at io.ktor.utils.io.ByteBufferChannel.writeFully$suspendImpl(ByteBufferChannel.kt:1094)
at io.ktor.utils.io.ByteBufferChannel.writeFully(ByteBufferChannel.kt)
at io.ktor.server.netty.cio.RequestBodyHandler.copy(RequestBodyHandler.kt:153)
at io.ktor.server.netty.cio.RequestBodyHandler.processContent(RequestBodyHandler.kt:110)
at io.ktor.server.netty.cio.RequestBodyHandler.access$processContent(RequestBodyHandler.kt:17)
at io.ktor.server.netty.cio.RequestBodyHandler$job$1.invokeSuspend(RequestBodyHandler.kt:42)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda-1$lambda-0(NettyApplicationEngine.kt:251)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Sample Codes
Applicaiton Main Function:
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
install(ContentNegotiation) {
jackson() // here replaced with json() or gson(), face with the same exception
}
configureRouting()
}.start(wait = true)
}
Routing handled the post request
fun Application.configureRouting() {
routing {
get("/") {
println("hahaha")
call.respondText("Hello World!")
}
post("/post") {
val requestBody = call.receive<Customer>()
call.respond(HttpStatusCode.OK, response)
}
}
}
Customer data class used to transfer the body
@Serializable
data class Customer(var name: String)
Gradle dependency
plugins {
application
kotlin("jvm") version "1.5.31"
kotlin("plugin.serialization") version "1.5.31"
}
dependencies {
implementation("io.ktor:ktor-jackson:$ktor_version")
implementation("io.ktor:ktor-serialization:$ktor_version")
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
testImplementation("io.ktor:ktor-server-tests:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}
Bump kotlinx.serialization to 1.3.0
Remove internal require and switch to Stdlib
Use the stdlib require
function instead of io.ktor.utils.io.core.internal.require
, with has the same signature.
Host parameter may contain illegal symbols
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/1862
Ktor Version and Engine Used (client or server and name)
io.ktor:ktor-server-cio:1.3.2
Describe the bug
"/", "?", "#", "@" symbols in 'Host' parameter value are prohibited(see https://tools.ietf.org/html/rfc2396#appendix-A)
To Reproduce
Steps to reproduce the behavior:
Run code:
import io.ktor.http.cio.parseRequest
import io.ktor.utils.io.ByteReadChannel
import kotlinx.coroutines.runBlocking
fun main() {
listOf(
"""
POST / HTTP/1.1
Host: www/example.com
""".trimIndent(),
"""
POST / HTTP/1.1
Host: www.example?com
""".trimIndent(),
"""
POST / HTTP/1.1
Host: www.ex#mple.com
""".trimIndent(),
"""
POST / HTTP/1.1
Host: www.ex@mple.com
""".trimIndent()
).forEach {
test(it)
}
}
fun test(http: String) {
val request = runBlocking { parseRequest(ByteReadChannel(http)) }!!
println("method=${request.method};uri={${request.uri}};headers=[${request.headers}]")
}
Expected behavior
An error expected - exception or null result.
Docs
Client logging: no description of default loggers' behavior on different platforms
There is no description in the documentation of what type of logger is used on different platforms by default, particularly on JVM and POSIX.
The default logger for JVM (Logger.DEFAULT
) is an slf4j logger that requires implementation, e.g Logback, and the default logger for POSIX (Logger.SIMPLE
) is just a logger that prints everything to stdout.
ktor-documentation code snippets - project e2e can't run
I can't make 'e2e' to start.
https://github.com/ktorio/ktor-documentation/tree/main/codeSnippets/snippets/e2e
Expected:
./gradlew :e2e:run
This has to work.
Generator
Generator: Follow Conventional Source Code Directory Structure
If the project's package is com.example.myProject
, the generated project will have the source files in e.g.
src/main/kotlin/com/example/myProject/Application.kt
But Kotlin's coding conventions suggests omitting the common root package from the directory structure:
src/main/kotlin/Application.kt
(Application.kt will still have package com.example.myProject
at the top of the file, of course)
From Kotlin's coding conventions page:
In pure Kotlin projects, the recommended directory structure follows the package structure with the common root package omitted. For example, if all the code in the project is in the org.example.kotlin package and its subpackages, files with the org.example.kotlin package should be placed directly under the source root, and files in org.example.kotlin.network.socket should be in the network/socket subdirectory of the source root.
Simplify plugin descriptions in wizard, remove empty options
Infrastructure
Ktor client 1.6.5 not published for 1.6.5
Its seems that the publish infrastructure is broken again and
https://search.maven.org/artifact/io.ktor/ktor-client-core-watchosx64/1.6.5
Wasn't published properly. It's however referenced in the module https://repo1.maven.org/maven2/io/ktor/ktor-client-core/1.6.5/ktor-client-core-1.6.5.module
Could not find tvOS in ktor-client
Hi!
In version 1.6.4 there are no problems, tvOS is supported without problems.
When upgrading the version to 1.6.5, it cannot find tvOS support.
FAILURE: Build completed with 2 failures.
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':shared:compileKotlinTvosArm64'.
> Could not resolve all files for configuration ':shared:tvosArm64CompileKlibraries'.
> Could not find io.ktor:ktor-client-core-tvosarm64:1.6.5.
Searched in the following locations:
- https://dl.google.com/dl/android/maven2/io/ktor/ktor-client-core-tvosarm64/1.6.5/ktor-client-core-tvosarm64-1.6.5.pom
- https://repo.maven.apache.org/maven2/io/ktor/ktor-client-core-tvosarm64/1.6.5/ktor-client-core-tvosarm64-1.6.5.pom
- https://oss.sonatype.org/content/repositories/snapshots/io/ktor/ktor-client-core-tvosarm64/1.6.5/ktor-client-core-tvosarm64-1.6.5.pom
Required by:
project :shared > io.ktor:ktor-client-core:1.6.5
> Could not find io.ktor:ktor-client-ios-tvosarm64:1.6.5.
Searched in the following locations:
- https://dl.google.com/dl/android/maven2/io/ktor/ktor-client-ios-tvosarm64/1.6.5/ktor-client-ios-tvosarm64-1.6.5.pom
- https://repo.maven.apache.org/maven2/io/ktor/ktor-client-ios-tvosarm64/1.6.5/ktor-client-ios-tvosarm64-1.6.5.pom
- https://oss.sonatype.org/content/repositories/snapshots/io/ktor/ktor-client-ios-tvosarm64/1.6.5/ktor-client-ios-tvosarm64-1.6.5.pom
Required by:
project :shared > io.ktor:ktor-client-ios:1.6.5
IntelliJ IDEA Plugin
Support test generation from endpoints
IDEA plugin missing the Session authentication
Currently, the plugin contains only the Sessions plugin. There is also a separate Session authentication provider: https://ktor.io/docs/session-auth.html
Wizard in IJ Idea Ultimate for creating a Ktor server plugin for future Marketplace upload
Server features instead of client in the client `install` block
`ContentNegotiation` is missing in the plugins completion window
Update Ktor Plugin Description
Can we please update the description to the following:
Ktor is a web application framework for creating connected systems. You can use it to create server-side as well as client-side applications. It supports multiple platforms, including JVM, JavaScript, and Kotlin/Native. This plugin provides functionality in the IDE such as creating new projects, plugin configuration, navigation (including URL navigation), refactorings across client and server, migrations, and more!
Project Generated with eap-256 has Errors in Imports
Server
CallLogging: JVM crashes when jansi checks whether a file descriptor refers to a terminal
стектрейс и инфо по окружению во вложении
Change default log level for CallLogging feature to INFO
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/319
The rational behind this proposal is that a production deployment of an application shall typically run with INFO
threshold on its logs (DEBUG
and TRACE
are typically used only for debugging of certain subsystems) and we expect that all requests shall be logged in a production deployment by default, since the log of requests represents the starting point for investigation of any production incidents.
NullPointerException if static file is not found
Currently, if you use a static file from the JVM resources like this
static {
resources()
}
and try accessing a file this error get's thrown instead of a 404
java.lang.NullPointerException: jarEntry must not be null
at io.ktor.http.content.JarFileContent.<init>(JarFileContent.kt:41)
at io.ktor.http.content.StaticContentResolutionKt.resourceClasspathResource(StaticContentResolution.kt:62)
at io.ktor.http.content.StaticContentResolutionKt.resolveResource(StaticContentResolution.kt:38)
at io.ktor.http.content.StaticContentResolutionKt.resolveResource$default(StaticContentResolution.kt:24)
at io.ktor.http.content.StaticContentKt$resources$1.invokeSuspend(StaticContent.kt:230)
at io.ktor.http.content.StaticContentKt$resources$1.invoke(StaticContent.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at com.homedia.backend.middleware.PublicKt$public$1$1.invokeSuspend(Public.kt:22)
at com.homedia.backend.middleware.PublicKt$public$1$1.invoke(Public.kt)
at com.homedia.backend.middleware.PublicKt$public$1$1.invoke(Public.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
at io.ktor.routing.Routing.executeResult(Routing.kt:155)
at io.ktor.routing.Routing.interceptor(Routing.kt:39)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:107)
at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:110)
at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:102)
at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:194)
at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:101)
at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:142)
at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.metrics.micrometer.MicrometerMetrics$Feature$install$2.invokeSuspend(MicrometerMetrics.kt:209)
at io.ktor.metrics.micrometer.MicrometerMetrics$Feature$install$2.invoke(MicrometerMetrics.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:124)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:246)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:123)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:158)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:43)
at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:34)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:370)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute$$$capture(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.ktor.server.netty.EventLoopGroupProxy$Companion$create$factory$1$1.run(NettyApplicationEngine.kt:241)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:831)
PartialContent need responed content length when respcode = 206
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/1995
now just range
[netty] Headers are only flushed after first byte is written
I've been trying to get a streaming response working for a while and I don't think it's currently possible to flush response headers before any byte is written when using the netty server engine. The exact same code works perfectly with cio.
The code looks something like this (I've tried using WriteChannelContent
with 0-byte writes and explicit flushes as well):
route("/timed") {
get {
val byteStream = ByteChannel(autoFlush = true)
launch(Dispatchers.Unconfined) {
delay(5000)
byteStream.writeFully(Charsets.UTF_8.encode("foo\n"))
byteStream.close(null)
}
call.respond(object : OutgoingContent.ReadChannelContent() {
override val status: HttpStatusCode? = HttpStatusCode.OK
override val contentType: ContentType? = ContentType.Text.Plain
override val headers: Headers = Headers.Empty
override fun readFrom() = byteStream
})
}
}
I'm testing with curl -XGET localhost:8080/timed -v
. When running the server with CIO this will immediately print the headers and then 5s later it'll print foo and close the response. With netty, this will wait for the full 5s before printing the whole response at once.
Writing multiple messages shows that this is only an issue with the initial header response. Streaming works fine with all messages after the initial byte.
Server CORS Plugin: Throw IllegalArgumentException if anyHost and allowCredentials is true
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials
install(CORS) {
anyHost()
allowCredentials = true
}
Expected: IAE during installing CORS plugin with this configuration
When working with SessionStorage, write is called every time after read
When using directorySessionStorage
or a custom implementation of SessionStorage
, I noticed that every time after the read function is called, the write function is called which invalidates the cache, making the use of the cache completely pointless.
Expected behavior: After the read SessionStorage
method is called, the write SessionStorage
method is not called.
Actual behavior: After the read SessionStorage
method is called, the write SessionStorage
method is also called.
Steps for reproduce:
-
Compile and run the code from the snippet
-
Authorize by sending HTTP POST request to http://localhost:9090/authenticate sending body in format x-www-form-urlencoded with user:user password:password, any data are considered correct, should return HTTP Status Code 200
-
Make sure authorization was successful and sending HTTP GET request to http://localhost:9090/hello returns HTTP Status Code 200 and "Hello World!" string.
When sending subsequent HTTP GET requests to http://localhost:9090/hello, the file with information about the session, which will be written to the /tmp folder, will be overwritten each time. Also, in the debugger in the io.ktor.sessions.CacheStorage
class, you can make sure that for each request the read method will be called and then the write method will be called.
Code to reproduce the issue:
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.application.*
import io.ktor.auth.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.sessions.*
import java.io.File
fun main() {
embeddedServer(Netty, port = 9090, host = "0.0.0.0") {
install(Authentication) {
session<UserIdPrincipal>("auth-session") {
validate { it }
challenge { call.respond(HttpStatusCode.Unauthorized) }
}
form("auth-form") {
validate { UserIdPrincipal(it.name) }
challenge { call.respond(HttpStatusCode.Forbidden) }
}
}
install(Sessions) {
cookie<UserIdPrincipal>(
"user_session",
directorySessionStorage(File("/tmp"))
)
}
routing {
authenticate("auth-form") {
post("/authenticate") {
val session = call.principal<UserIdPrincipal>()
call.sessions.set(session)
call.respond(HttpStatusCode.OK)
}
}
}
routing {
authenticate("auth-session") {
get("/hello") {
call.respondText("Hello World!")
}
}
}
}.start(wait = true)
}
Responding without contentLength freezes on CIO native
@Test
fun testChunked() {
createAndStartServer {
handle {
call.respond(object : OutgoingContent.ByteArrayContent() {
override val status: HttpStatusCode = HttpStatusCode.OK
override val headers: Headers = Headers.Empty
override fun bytes() = ByteArray(5) { it.toByte() }
})
}
}
withUrl("/") {
assertEquals(200, status.value)
}
}
adding override val contentLength: Long = 5
fixes freezing
Prototype anchors in new plugins API
- Deduce a set of anchors that may check piepline state
- Implement anchors API (
beforeAnchor
/afterAnchor
) - Each anchor must have its own "receiver type" that will be applied in
beforeAnchor
/afterAnchor
block. It defines which handlers (onCall
,onCallReceive
, ...) are relevant and present and which are not. - Get rid of standard phases, use anchors instead!
onCallReceive
should insert to call receive pipelineonCallReceive
should insert to the same pipeline but before/after some anchor
Some Netty EngineMain properties are not set
Ktor Version
1.6.4
Ktor Engine Used
Netty Server
Behaviour
Only some of NettyApplicationEngine
's properties are loaded from ApplicationConfig
set when using EngineMain
.
Expected behaviour
After reading https://ktor.io/docs/engines.html#configure-engine I assumed it would be possible to configure all properties (besides the functions) via the configuration files.
Missing runningLimit
, requestReadTimeoutSeconds
and tcpKeepAlive
java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled
This issue was imported from GitHub issue: https://github.com/ktorio/ktor/issues/1652
Hi all
When I run my Ktor application with gradle run then I've got the following exception:
19:21:11.795 [main] DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
19:21:11.810 [main] DEBUG io.netty.util.internal.PlatformDependent0 - -Dio.netty.noUnsafe: false
19:21:11.810 [main] DEBUG io.netty.util.internal.PlatformDependent0 - Java version: 11
19:21:11.811 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
19:21:11.812 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
19:21:11.812 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
19:21:11.814 [main] DEBUG io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable
java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled
at io.netty.util.internal.ReflectionUtil.trySetAccessible(ReflectionUtil.java:31)
at io.netty.util.internal.PlatformDependent0$4.run(PlatformDependent0.java:225)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at io.netty.util.internal.PlatformDependent0.<clinit>(PlatformDependent0.java:219)
at io.netty.util.internal.PlatformDependent.isAndroid(PlatformDependent.java:273)
at io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:92)
at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:225)
at io.netty.channel.epoll.Native.<clinit>(Native.java:57)
at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:39)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create(NettyApplicationEngine.kt:189)
at io.ktor.server.netty.NettyApplicationEngine.<init>(NettyApplicationEngine.kt:74)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:22)
19:21:11.814 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: available, true
19:21:11.815 [main] DEBUG io.netty.util.internal.PlatformDependent0 - jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable
java.lang.IllegalAccessException: class io.netty.util.internal.PlatformDependent0$6 cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @557caf28
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Method.invoke(Method.java:558)
at io.netty.util.internal.PlatformDependent0$6.run(PlatformDependent0.java:335)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at io.netty.util.internal.PlatformDependent0.<clinit>(PlatformDependent0.java:326)
at io.netty.util.internal.PlatformDependent.isAndroid(PlatformDependent.java:273)
at io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:92)
at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:225)
at io.netty.channel.epoll.Native.<clinit>(Native.java:57)
at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:39)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create(NettyApplicationEngine.kt:189)
at io.ktor.server.netty.NettyApplicationEngine.<init>(NettyApplicationEngine.kt:74)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:22)
the content of build.gradle.kts file
plugins {
application
kotlin("jvm") version "1.3.61"
}
group = "io.flatmap"
version = "1.0-SNAPSHOT"
val ktor_version = "1.3.0"
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
compile("io.ktor:ktor-server-netty:$ktor_version")
compile("io.ktor:ktor-server-core:$ktor_version")
compile("ch.qos.logback:logback-classic:1.2.3")
testCompile(group = "junit", name = "junit", version = "4.12")
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "11"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "11"
}
}
application {
mainClassName = "io.ktor.server.netty.EngineMain"
}
I am using Zulu OpenJDK 11:
java --version
openjdk 11.0.6 2020-01-14 LTS
OpenJDK Runtime Environment Zulu11.37+17-CA (build 11.0.6+10-LTS)
OpenJDK 64-Bit Server VM Zulu11.37+17-CA (build 11.0.6+10-LTS, mixed mode)
I thought, this is solved through https://github.com/ktorio/ktor/issues/1190.
Thanks
Test Infrastructure
Add support for sending request params in tests
https://ktor.io/docs/testing.html describes how to send body and how to set headers for test requests; however, there doesn't seem to be a way to programatically set request parameters. It is possible to inline them in URL itself, but it is very inelegant.
If this is desired functionality, I can try sending a PR :)
Other
Binary compatibility issue with Ktor 1.6.5 (affecting JDK 1.8 & 11 users)
I haven't checked the details yet but some tests using Ktor's testing module in our project detected a binary-compatibility issue.
As a workaround, we locked the version to 1.6.4 and it worked for us. https://github.com/slackapi/java-slack-sdk/commit/8a9063bf694376074a3a4bed93871416f48241c3
I hope this helps.
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer;
at io.ktor.utils.io.ByteBufferChannel.prepareBuffer(ByteBufferChannel.kt:231)
at io.ktor.utils.io.ByteBufferChannel.setupStateForWrite$ktor_io(ByteBufferChannel.kt:285)
at io.ktor.utils.io.ByteBufferChannel.writeAsMuchAsPossible(ByteBufferChannel.kt:3487)
at io.ktor.utils.io.ByteBufferChannel.writeFully$suspendImpl(ByteBufferChannel.kt:1425)
at io.ktor.utils.io.ByteBufferChannel.writeFully(ByteBufferChannel.kt)
at io.ktor.utils.io.ByteWriteChannelKt.writeFully(ByteWriteChannel.kt:152)
at io.ktor.server.engine.BaseApplicationResponse$respondFromBytes$3$1.invokeSuspend(BaseApplicationResponse.kt:191)
at (Coroutine boundary.()
at io.ktor.server.engine.DefaultTransformKt$installDefaultTransformations$1.invokeSuspend(DefaultTransform.kt:35)
at test_locally.app.events.TestKt$main$2$1.invokeSuspend(test.kt:42)
at io.ktor.routing.Routing.executeResult(Routing.kt:154)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:107)
at io.ktor.server.testing.TestApplicationEngine$callInterceptor$1.invokeSuspend(TestApplicationEngine.kt:296)
at io.ktor.server.testing.TestApplicationEngine$2.invokeSuspend(TestApplicationEngine.kt:50)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$pipelineJob$1.invokeSuspend(TestApplicationEngine.kt:295)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$1.invokeSuspend(TestApplicationEngine.kt:153)
Please allow CORS `anyHost()` in combination with `allowCredentials`
The combination from the title is not allowed, as per:
if (configuration.allowCredentials) {
require(!allowsAnyHost) {
"AnyHost * is not allowed in combination with Allow-Credentials, see " +
"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials."
}
}
However, while the specific combination of responding with Access-Control-Allow-Origin: *
and allowing credentials may be illegal, that doesn't mean it should be impossible to allow any host to perform a request with credentials. All that's needed is responding with Access-Control-Allow-Origin: $requestOrigin
if credentials are to be allowed:
private fun ApplicationCall.accessControlAllowOrigin(origin: String) {
if (allowsAnyHost && !allowCredentials) { // <--- modification here
response.header(HttpHeaders.AccessControlAllowOrigin, "*")
} else {
response.header(HttpHeaders.AccessControlAllowOrigin, origin)
}
}
(by the way, yes, I am aware of the security implications)
Disable `expectSuccess` by default
Migrate to new kotlinx.coroutines and `limited` dispatcher(revert corePoolSize option)
Add Defaults for the server.stop Method
io.ktor.utils.io.bits.MemoryJvmKt.sliceSafe (MemoryJvmKt.java:211)
Ktor Version: 1.6.5
Ktor client: io.ktor:ktor-client-android
Platform: Android
Kotlin version: 1.5.31
Java version: 1.8
Describe the bug
No virtual method position(I)Ljava/nio/ByteBuffer; in class Ljava/nio/ByteBuffer; or its super classes (declaration of 'java.nio.ByteBuffer' appears in /system/framework/core-oj.jar)
io.ktor.utils.io.bits.MemoryJvmKt.sliceSafe (MemoryJvmKt.java:211)
io.ktor.utils.io.bits.Memory.slice-SK3TCg8 (Memory.java:47)
io.ktor.utils.io.core.IoBufferJVMKt.writeDirect$default (IoBufferJVMKt.java:557)
io.ktor.utils.io.charsets.CharsetJVMKt.encodeImpl (CharsetJVMKt.java:356)
io.ktor.utils.io.charsets.EncodingKt.encodeToImpl (EncodingKt.java:204)
io.ktor.utils.io.charsets.EncodingKt.encode (EncodingKt.java:62)
io.ktor.utils.io.charsets.EncodingKt.encode$default (EncodingKt.java:57)
io.ktor.http.CodecsKt.encodeURLParameter (CodecsKt.java:122)
io.ktor.http.HttpUrlEncodedKt$formUrlEncodeTo$1.invoke (HttpUrlEncodedKt.java:68)
io.ktor.http.HttpUrlEncodedKt$formUrlEncodeTo$1.invoke (HttpUrlEncodedKt.java:67)
kotlin.text.StringsKt__AppendableKt.appendElement (StringsKt__AppendableKt.java:85)
kotlin.text.StringsKt.appendElement (StringsKt.java)
kotlin.collections.CollectionsKt___CollectionsKt.joinTo (CollectionsKt___CollectionsKt.java:3344)
kotlin.collections.CollectionsKt___CollectionsKt.joinTo$default (CollectionsKt___CollectionsKt.java:3338)
kotlin.collections.CollectionsKt.joinTo$default (CollectionsKt.java)
io.ktor.http.HttpUrlEncodedKt.formUrlEncodeTo (HttpUrlEncodedKt.java:67)
io.ktor.http.HttpUrlEncodedKt.formUrlEncodeTo (HttpUrlEncodedKt.java:108)
io.ktor.http.HttpUrlEncodedKt.formUrlEncodeTo (HttpUrlEncodedKt.java:90)
io.ktor.http.URLUtilsKt.appendUrlFullPath (URLUtilsKt.java:101)
io.ktor.http.URLUtilsKt.getFullPath (URLUtilsKt.java:79)
io.ktor.http.Url.toString (Url.java:169)
java.lang.String.valueOf (String.java:2683)
java.lang.StringBuilder.append (StringBuilder.java:129)
io.ktor.client.features.logging.Logging.logRequestException (Logging.java:116)
io.ktor.client.features.logging.Logging.access$logResponseException (Logging.java:25)
io.ktor.client.features.logging.Logging$Companion$install$1.invokeSuspend (Logging.java:178)
Multiple messages around upgrading to new version
Drop `client.get` Operator Because of Ambiguity with `get(URL)` breaking-change
Drop Old Patch Releases from API Docs to Reduce Space Consumption
We should drop everything before 1.6.6
Change log level from `INFO` to `ERROR` for tests only
webSocketSession freeze every time
The method freezes without response:
public suspend fun HttpClient.webSocketSession(
block: HttpRequestBuilder.() -> Unit
): DefaultClientWebSocketSession
Exceptions are Swallowed in `HttpClient.wss` block
When the exception fails in:
client.wss {
error("error")
}
It will be swallowed and can either freeze or fail with unrelated cause.
Support receiving headers before sending body in CIO client engine
Update Kotlin to 1.6.0
Provide color on log out when running application.
Distinguishing green, yellow, red.
Implement new `Locations` feature
Fix old metadata publication
Move Server Related Code from `ktor-http-cio` to `ktor-server-cio` breaking-change
Add Check if Feature is installed for `WebSocket` builders
Right now calling client.ws
method without feature triggers failed to convert class
exception, it should check for the feature installed and fail early instead
Connection Reset when using pebble feature in 1.6.5
I'm getting some strange behavior when using pebble with 1.6.5. It seems to get caught in some loop when serving pebble content. I confirmed that this behavior does not exist in 1.6.4. I have attached a sample project to this, if you try to hit localhost:8080/
it will reproduce.
The setup is relatively simple, serving just about any pebble file seems to make this crash.
Output after a single call to localhost:8080/
2021-11-19 11:17:13.587 [main] INFO Application - Responding at http://0.0.0.0:8080
2021-11-19 11:17:13.589 [main] INFO Application - Application started in 0.635 seconds.
2021-11-19 11:17:13.589 [main] INFO Application - Application started: io.ktor.application.Application@56aaaecd
2021-11-19 11:17:15.425 [eventLoopGroupProxy-4-1] DEBUG c.m.pebble.loader.ClasspathLoader - Looking for template in templates/index.pbl.
2021-11-19 11:17:15.427 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.PebbleEngine - Tokenizing template named templates/index.pbl
2021-11-19 11:17:15.430 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 2
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Skipping empty text token
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=1]
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=extends, type=NAME, lineNumber=1]
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 7
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.431 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 20
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=templates/main.pbl, type=STRING, lineNumber=1]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=1]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 3
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=
, type=TEXT, lineNumber=3]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=3]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=block, type=NAME, lineNumber=3]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 5
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=content, type=NAME, lineNumber=3]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 7
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=3]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 71
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value= <div id="root"></div>
<script src="assets/main.js"></script>
, type=TEXT, lineNumber=6]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=6]
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.432 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=endblock, type=NAME, lineNumber=6]
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 8
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=6]
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EOF, lineNumber=7]
2021-11-19 11:17:15.433 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.PebbleEngine - TokenStream: Current: Token [value=null, type=EXECUTE_START, lineNumber=1]. All: [Token [value=null, type=EXECUTE_START, lineNumber=1], Token [value=extends, type=NAME, lineNumber=1], Token [value=templates/main.pbl, type=STRING, lineNumber=1], Token [value=%}, type=EXECUTE_END, lineNumber=1], Token [value=
, type=TEXT, lineNumber=3], Token [value=null, type=EXECUTE_START, lineNumber=3], Token [value=block, type=NAME, lineNumber=3], Token [value=content, type=NAME, lineNumber=3], Token [value=%}, type=EXECUTE_END, lineNumber=3], Token [value= <div id="root"></div>
<script src="assets/main.js"></script>
, type=TEXT, lineNumber=6], Token [value=null, type=EXECUTE_START, lineNumber=6], Token [value=endblock, type=NAME, lineNumber=6], Token [value=%}, type=EXECUTE_END, lineNumber=6], Token [value=null, type=EOF, lineNumber=7]]
2021-11-19 11:17:15.443 [eventLoopGroupProxy-4-1] DEBUG c.m.pebble.loader.ClasspathLoader - Looking for template in templates/main.pbl.
2021-11-19 11:17:15.443 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.PebbleEngine - Tokenizing template named templates/main.pbl
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 150
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
, type=TEXT, lineNumber=6]
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=6]
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=if, type=NAME, lineNumber=6]
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 2
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=description, type=NAME, lineNumber=6]
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 11
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.444 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=6]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {{
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 40
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value= <meta name="description" content=", type=TEXT, lineNumber=7]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=PRINT_START, lineNumber=7]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=description, type=NAME, lineNumber=7]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 11
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=}}, type=PRINT_END, lineNumber=7]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 3
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 11
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=" />
, type=TEXT, lineNumber=8]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=8]
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.445 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=else, type=NAME, lineNumber=8]
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=8]
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 56
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value= <meta name="description" content="project" />
, type=TEXT, lineNumber=10]
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=10]
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=endif, type=NAME, lineNumber=10]
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 5
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.446 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=10]
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 7
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=
, type=TEXT, lineNumber=12]
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=12]
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=if, type=NAME, lineNumber=12]
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 2
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=title, type=NAME, lineNumber=12]
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 5
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=12]
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.447 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {{
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 13
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value= <title>, type=TEXT, lineNumber=13]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=PRINT_START, lineNumber=13]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=title, type=NAME, lineNumber=13]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 5
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=}}, type=PRINT_END, lineNumber=13]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 3
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 15
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=</title>
, type=TEXT, lineNumber=14]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=14]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=else, type=NAME, lineNumber=14]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=14]
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.448 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 33
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value= <title>project</title>
, type=TEXT, lineNumber=16]
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=16]
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=endif, type=NAME, lineNumber=16]
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 5
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=16]
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 93
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value= <link rel="stylesheet" href="/assets/styles/main.css" as="style" />
</head>
<body>
, type=TEXT, lineNumber=20]
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=20]
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.449 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=block, type=NAME, lineNumber=20]
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 5
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=content, type=NAME, lineNumber=20]
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 7
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=20]
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 3
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {{
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 2
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Skipping empty text token
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=PRINT_START, lineNumber=20]
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=content, type=NAME, lineNumber=20]
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 7
2021-11-19 11:17:15.450 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=|, type=OPERATOR, lineNumber=20]
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 1
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=safe, type=NAME, lineNumber=20]
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=}}, type=PRINT_END, lineNumber=20]
2021-11-19 11:17:15.451 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 3
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Start Deliminter Token string: {%
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 2
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Skipping empty text token
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EXECUTE_START, lineNumber=20]
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Expression
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advanced through 1 characters of whitespace.
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=endblock, type=NAME, lineNumber=20]
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 8
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenize between execute delimiters
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=%}, type=EXECUTE_END, lineNumber=20]
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 4
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Tokenizing Data
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Advancing to the end of the template because no start delimiter was found
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.TemplateSource - Advancing amount: 16
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=</body>
</html>
, type=TEXT, lineNumber=23]
2021-11-19 11:17:15.453 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.lexer.LexerImpl - Pushing Token: Token [value=null, type=EOF, lineNumber=23]
2021-11-19 11:17:15.454 [eventLoopGroupProxy-4-1] TRACE c.m.pebble.PebbleEngine - TokenStream: Current: Token [value=<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
, type=TEXT, lineNumber=6]. All: [Token [value=<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
, type=TEXT, lineNumber=6], Token [value=null, type=EXECUTE_START, lineNumber=6], Token [value=if, type=NAME, lineNumber=6], Token [value=description, type=NAME, lineNumber=6], Token [value=%}, type=EXECUTE_END, lineNumber=6], Token [value= <meta name="description" content=", type=TEXT, lineNumber=7], Token [value=null, type=PRINT_START, lineNumber=7], Token [value=description, type=NAME, lineNumber=7], Token [value=}}, type=PRINT_END, lineNumber=7], Token [value=" />
, type=TEXT, lineNumber=8], Token [value=null, type=EXECUTE_START, lineNumber=8], Token [value=else, type=NAME, lineNumber=8], Token [value=%}, type=EXECUTE_END, lineNumber=8], Token [value= <meta name="description" content="project" />
, type=TEXT, lineNumber=10], Token [value=null, type=EXECUTE_START, lineNumber=10], Token [value=endif, type=NAME, lineNumber=10], Token [value=%}, type=EXECUTE_END, lineNumber=10], Token [value=
, type=TEXT, lineNumber=12], Token [value=null, type=EXECUTE_START, lineNumber=12], Token [value=if, type=NAME, lineNumber=12], Token [value=title, type=NAME, lineNumber=12], Token [value=%}, type=EXECUTE_END, lineNumber=12], Token [value= <title>, type=TEXT, lineNumber=13], Token [value=null, type=PRINT_START, lineNumber=13], Token [value=title, type=NAME, lineNumber=13], Token [value=}}, type=PRINT_END, lineNumber=13], Token [value=</title>
, type=TEXT, lineNumber=14], Token [value=null, type=EXECUTE_START, lineNumber=14], Token [value=else, type=NAME, lineNumber=14], Token [value=%}, type=EXECUTE_END, lineNumber=14], Token [value= <title>project</title>
, type=TEXT, lineNumber=16], Token [value=null, type=EXECUTE_START, lineNumber=16], Token [value=endif, type=NAME, lineNumber=16], Token [value=%}, type=EXECUTE_END, lineNumber=16], Token [value= <link rel="stylesheet" href="/assets/styles/main.css" as="style" />
</head>
<body>
, type=TEXT, lineNumber=20], Token [value=null, type=EXECUTE_START, lineNumber=20], Token [value=block, type=NAME, lineNumber=20], Token [value=content, type=NAME, lineNumber=20], Token [value=%}, type=EXECUTE_END, lineNumber=20], Token [value=null, type=PRINT_START, lineNumber=20], Token [value=content, type=NAME, lineNumber=20], Token [value=|, type=OPERATOR, lineNumber=20], Token [value=safe, type=NAME, lineNumber=20], Token [value=}}, type=PRINT_END, lineNumber=20], Token [value=null, type=EXECUTE_START, lineNumber=20], Token [value=endblock, type=NAME, lineNumber=20], Token [value=%}, type=EXECUTE_END, lineNumber=20], Token [value=</body>
</html>
, type=TEXT, lineNumber=23], Token [value=null, type=EOF, lineNumber=23]]
2021-11-19 11:17:15.544 [eventLoopGroupProxy-4-8] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-4] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-3] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-7] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.544 [eventLoopGroupProxy-4-5] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.544 [eventLoopGroupProxy-4-6] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-2] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-10] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-9] INFO Application - 200 OK: GET - /
2021-11-19 11:17:15.545 [eventLoopGroupProxy-4-1] INFO Application - 200 OK: GET - /
Firefox will display connection was reset.
IJ locked after attempt to create new run config in a dialog
What steps will reproduce the issue?
1. Open Run/Debug configurations
2. Click on +
to create new config
3. wait 10+ mins
4. IJ locked and dialog not going away: neither Cancel not window close actions works
5. report here
What is the expected result?
Dialog not blocking use of IJ
What happens instead?
Please attach the IDE logs to the issue. You can get them by selecting Collect Logs and Diagnostic Data from the Help menu.
2021-11-04 12:35:31
Full thread dump OpenJDK 64-Bit Server VM (11.0.13+7-b1751.16 mixed mode):
Threads class SMR info:
_java_thread_list=0x000060000f5efd00, length=60, elements={
0x00007fdd63020800, 0x00007fdd63024000, 0x00007fdd53014000, 0x00007fdd8400c000,
0x00007fdd8380b000, 0x00007fdd85097000, 0x00007fdd8507c800, 0x00007fdd85054800,
0x00007fdd8386f000, 0x00007fdd43049800, 0x00007fdd8385d800, 0x00007fdd84069000,
0x00007fdd838a4000, 0x00007fdd63144000, 0x00007fdd53136000, 0x00007fdd852b5000,
0x00007fdd3300e000, 0x00007fdd431fb000, 0x00007fdd23008800, 0x00007fdd53450800,
0x00007fdd26010000, 0x00007fdd852a6800, 0x00007fdd33012000, 0x00007fdd8413a000,
0x00007fdd53495000, 0x00007fdd8525b800, 0x00007fdd53675000, 0x00007fdd2602b000,
0x00007fdd53152000, 0x00007fdd535fd800, 0x00007fdd84382800, 0x00007fdd84383800,
0x00007fdd634a8800, 0x00007fdd6349c800, 0x00007fdd6349d800, 0x00007fdd43570800,
0x00007fdd83ac3000, 0x00007fdd33884800, 0x00007fdd33840800, 0x00007fdd84466800,
0x00007fdd23020000, 0x00007fdd63063000, 0x00007fdd84664000, 0x00007fdd33827800,
0x00007fdce7313000, 0x00007fdd8575d000, 0x00007fdd6367e000, 0x00007fdd63222000,
0x00007fdce7135000, 0x00007fdd53580800, 0x00007fdd83dde000, 0x00007fdd31d7e000,
0x00007fdd436ed000, 0x00007fdd5350d800, 0x00007fdd83cb5000, 0x00007fdce7334000,
0x00007fdd23052800, 0x00007fdd8482b000, 0x00007fdd2484d800, 0x00007fdd31a79800
}
"Reference Handler" #2 daemon prio=10 os_prio=31 cpu=133.49ms elapsed=1146.59s tid=0x00007fdd63020800 nid=0x3e03 waiting on condition [0x000070000d211000]
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@11.0.13/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@11.0.13/Reference.java:241)
at java.lang.ref.Reference$ReferenceHandler.run(java.base@11.0.13/Reference.java:213)
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=31 cpu=14.32ms elapsed=1146.59s tid=0x00007fdd63024000 nid=0x3d03 in Object.wait() [0x000070000d314000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:155)
- waiting to re-lock in wait() <0x000000060ca00178> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:176)
at java.lang.ref.Finalizer$FinalizerThread.run(java.base@11.0.13/Finalizer.java:170)
Locked ownable synchronizers:
- None
"Signal Dispatcher" #4 daemon prio=9 os_prio=31 cpu=0.40ms elapsed=1146.58s tid=0x00007fdd53014000 nid=0xa803 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Service Thread" #5 daemon prio=9 os_prio=31 cpu=418.74ms elapsed=1146.58s tid=0x00007fdd8400c000 nid=0xa503 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 cpu=170146.81ms elapsed=1146.58s tid=0x00007fdd8380b000 nid=0xa203 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
No compile task
Locked ownable synchronizers:
- None
"C1 CompilerThread0" #7 daemon prio=9 os_prio=31 cpu=35932.81ms elapsed=1146.58s tid=0x00007fdd85097000 nid=0x5803 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
No compile task
Locked ownable synchronizers:
- None
"Sweeper thread" #8 daemon prio=9 os_prio=31 cpu=946.73ms elapsed=1146.58s tid=0x00007fdd8507c800 nid=0x5a03 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Common-Cleaner" #9 daemon prio=8 os_prio=31 cpu=18.65ms elapsed=1146.55s tid=0x00007fdd85054800 nid=0x9f03 in Object.wait() [0x000070000d926000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:155)
- waiting to re-lock in wait() <0x000000060ca21e88> (a java.lang.ref.ReferenceQueue$Lock)
at jdk.internal.ref.CleanerImpl.run(java.base@11.0.13/CleanerImpl.java:148)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
at jdk.internal.misc.InnocuousThread.run(java.base@11.0.13/InnocuousThread.java:134)
Locked ownable synchronizers:
- None
"AWT-AppKit" #13 daemon prio=5 os_prio=31 cpu=4723.92ms elapsed=1146.31s tid=0x00007fdd8386f000 nid=0x103 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Timer-0" #14 daemon prio=4 os_prio=31 cpu=1.44ms elapsed=1146.27s tid=0x00007fdd43049800 nid=0x7f03 in Object.wait() [0x000070000dfbe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.Object.wait(java.base@11.0.13/Object.java:328)
at java.util.TimerThread.mainLoop(java.base@11.0.13/Timer.java:527)
- waiting to re-lock in wait() <0x000000060ca64bb8> (a java.util.TaskQueue)
at java.util.TimerThread.run(java.base@11.0.13/Timer.java:506)
Locked ownable synchronizers:
- None
"AWT-Shutdown" #16 prio=5 os_prio=31 cpu=1.95ms elapsed=1146.25s tid=0x00007fdd8385d800 nid=0x1530b in Object.wait() [0x000070000e0c1000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.Object.wait(java.base@11.0.13/Object.java:328)
at sun.awt.AWTAutoShutdown.run(java.desktop@11.0.13/AWTAutoShutdown.java:291)
- waiting to re-lock in wait() <0x000000060ca43480> (a java.lang.Object)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"AWT-EventQueue-0" #17 prio=6 os_prio=31 cpu=621820.38ms elapsed=1146.18s tid=0x00007fdd84069000 nid=0xd103 runnable [0x000070000e2be000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.putVal(java.base@11.0.13/HashMap.java:653)
at java.util.HashMap.put(java.base@11.0.13/HashMap.java:608)
at java.util.HashSet.add(java.base@11.0.13/HashSet.java:220)
at java.util.AbstractCollection.addAll(java.base@11.0.13/AbstractCollection.java:352)
at org.jetbrains.kotlin.idea.caches.project.GetModuleInfoKt$lazyClosure$1.invokeSuspend(getModuleInfo.kt:324)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.sequences.SequenceBuilderIterator.hasNext(SequenceBuilder.kt:140)
at org.jetbrains.kotlin.idea.caches.project.SdkInfoCacheImpl.doFindSdk(SdkInfoCache.kt:46)
at org.jetbrains.kotlin.idea.caches.project.SdkInfoCacheImpl.findOrGetCachedSdk(SdkInfoCache.kt:37)
at org.jetbrains.kotlin.idea.caches.project.GetModuleInfoKt.findSdkAcrossDependencies(getModuleInfo.kt:44)
at org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject.sdkDependency(IdeaResolverForProject.kt:85)
at org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject$BuiltInsCache$getOrCreateIfNeeded$1.invoke(IdeaResolverForProject.kt:167)
at org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject$BuiltInsCache$getOrCreateIfNeeded$1.invoke(IdeaResolverForProject.kt:163)
at org.jetbrains.kotlin.storage.LockBasedStorageManager.compute(LockBasedStorageManager.java:290)
at org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject$BuiltInsCache.getOrCreateIfNeeded(IdeaResolverForProject.kt:166)
at org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject.builtInsForModule(IdeaResolverForProject.kt:91)
at org.jetbrains.kotlin.idea.caches.resolve.IdeaResolverForProject.builtInsForModule(IdeaResolverForProject.kt:39)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.createModuleDescriptor(AbstractResolverForProject.kt:205)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.access$createModuleDescriptor(AbstractResolverForProject.kt:17)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject$doGetDescriptorForModule$1.invoke(AbstractResolverForProject.kt:175)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject$doGetDescriptorForModule$1.invoke(AbstractResolverForProject.kt:173)
at org.jetbrains.kotlin.storage.LockBasedStorageManager.compute(LockBasedStorageManager.java:290)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.doGetDescriptorForModule(AbstractResolverForProject.kt:173)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.descriptorForModule(AbstractResolverForProject.kt:150)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.descriptorForModule(AbstractResolverForProject.kt:17)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.doGetDescriptorForModule(AbstractResolverForProject.kt:171)
at org.jetbrains.kotlin.analyzer.AbstractResolverForProject.descriptorForModule(AbstractResolverForProject.kt:150)
at org.jetbrains.kotlin.analyzer.LazyModuleDependencies$dependencies$1.invoke(AnalyzerFacade.kt:164)
at org.jetbrains.kotlin.analyzer.LazyModuleDependencies$dependencies$1.invoke(AnalyzerFacade.kt:146)
at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
at org.jetbrains.kotlin.analyzer.LazyModuleDependencies.getAllDependencies(AnalyzerFacade.kt:174)
at org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl$packageFragmentProviderForWholeModuleWithDependencies$2.invoke(ModuleDescriptorImpl.kt:95)
at org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl$packageFragmentProviderForWholeModuleWithDependencies$2.invoke(ModuleDescriptorImpl.kt:93)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
- locked <0x0000000684c49498> (a kotlin.SynchronizedLazyImpl)
at org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl.getPackageFragmentProviderForWholeModuleWithDependencies(ModuleDescriptorImpl.kt:93)
at org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl.getPackageFragmentProvider(ModuleDescriptorImpl.kt:150)
at org.jetbrains.kotlin.descriptors.impl.LazyPackageViewDescriptorImpl$fragments$2.invoke(LazyPackageViewDescriptorImpl.kt:38)
at org.jetbrains.kotlin.descriptors.impl.LazyPackageViewDescriptorImpl$fragments$2.invoke(LazyPackageViewDescriptorImpl.kt:37)
at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
at org.jetbrains.kotlin.storage.StorageKt.getValue(storage.kt:42)
at org.jetbrains.kotlin.descriptors.impl.LazyPackageViewDescriptorImpl.getFragments(LazyPackageViewDescriptorImpl.kt:37)
at org.jetbrains.kotlin.descriptors.impl.LazyPackageViewDescriptorImpl$memberScope$1.invoke(LazyPackageViewDescriptorImpl.kt:42)
at org.jetbrains.kotlin.descriptors.impl.LazyPackageViewDescriptorImpl$memberScope$1.invoke(LazyPackageViewDescriptorImpl.kt:41)
at org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter$lazyScope$1.invoke(LazyScopeAdapter.kt:28)
at org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter$lazyScope$1.invoke(LazyScopeAdapter.kt:27)
at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
at org.jetbrains.kotlin.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
at org.jetbrains.kotlin.resolve.scopes.LazyScopeAdapter.getWorkerScope(LazyScopeAdapter.kt:34)
at org.jetbrains.kotlin.resolve.scopes.AbstractScopeAdapter.getContributedClassifier(AbstractScopeAdapter.kt:44)
at org.jetbrains.kotlin.descriptors.FindClassInModuleKt.findClassifierAcrossModuleDependencies(findClassInModule.kt:26)
at org.jetbrains.kotlin.descriptors.FindClassInModuleKt.findClassAcrossModuleDependencies(findClassInModule.kt:48)
at io.ktor.initializr.intellij.run.KtorLibraryUtilKt.hasKtorLibrary(KtorLibraryUtil.kt:40)
at io.ktor.initializr.intellij.run.KtorLibraryUtilKt.hasKtorLibrary(KtorLibraryUtil.kt:31)
at io.ktor.initializr.intellij.run.KtorRunConfigurationType$myFactory$1.isApplicable(KtorRunConfigurationType.kt:28)
at com.intellij.execution.impl.RunConfigurable$Companion.getTypesToShow(RunConfigurable.kt:154)
at com.intellij.execution.impl.RunConfigurable$Companion.configurationTypeSorted(RunConfigurable.kt:148)
at com.intellij.execution.impl.RunConfigurable$MyToolbarAddAction.showAddPopup(RunConfigurable.kt:918)
at com.intellij.execution.impl.RunConfigurable$MyToolbarAddAction.run(RunConfigurable.kt:912)
at com.intellij.execution.impl.RunConfigurable$MyToolbarAddAction.run(RunConfigurable.kt:898)
at com.intellij.ui.ToolbarDecorator$3.doAdd(ToolbarDecorator.java:528)
at com.intellij.ui.CommonActionsPanel$AddButton.actionPerformed(CommonActionsPanel.java:315)
at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:172)
at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:151)
at com.intellij.openapi.actionSystem.impl.ActionButton$$Lambda$6320/0x0000000803eb0040.run(Unknown Source)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:265)
at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:151)
at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:433)
at java.awt.Component.processEvent(java.desktop@11.0.13/Component.java:6419)
at java.awt.Container.processEvent(java.desktop@11.0.13/Container.java:2263)
at java.awt.Component.dispatchEventImpl(java.desktop@11.0.13/Component.java:5029)
at java.awt.Container.dispatchEventImpl(java.desktop@11.0.13/Container.java:2321)
at java.awt.Component.dispatchEvent(java.desktop@11.0.13/Component.java:4861)
at java.awt.LightweightDispatcher.retargetMouseEvent(java.desktop@11.0.13/Container.java:4918)
at java.awt.LightweightDispatcher.processMouseEvent(java.desktop@11.0.13/Container.java:4547)
at java.awt.LightweightDispatcher.dispatchEvent(java.desktop@11.0.13/Container.java:4488)
at java.awt.Container.dispatchEventImpl(java.desktop@11.0.13/Container.java:2307)
at java.awt.Window.dispatchEventImpl(java.desktop@11.0.13/Window.java:2790)
at java.awt.Component.dispatchEvent(java.desktop@11.0.13/Component.java:4861)
at java.awt.EventQueue.dispatchEventImpl(java.desktop@11.0.13/EventQueue.java:778)
at java.awt.EventQueue$4.run(java.desktop@11.0.13/EventQueue.java:727)
at java.awt.EventQueue$4.run(java.desktop@11.0.13/EventQueue.java:721)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@11.0.13/ProtectionDomain.java:85)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@11.0.13/ProtectionDomain.java:95)
at java.awt.EventQueue$5.run(java.desktop@11.0.13/EventQueue.java:751)
at java.awt.EventQueue$5.run(java.desktop@11.0.13/EventQueue.java:749)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@11.0.13/ProtectionDomain.java:85)
at java.awt.EventQueue.dispatchEvent(java.desktop@11.0.13/EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
at com.intellij.ide.IdeEventQueue$$Lambda$557/0x00000008005db040.compute(Unknown Source)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
at com.intellij.ide.IdeEventQueue$$Lambda$555/0x00000008005d9c40.run(Unknown Source)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
at java.awt.EventDispatchThread.pumpOneEventForFilters(java.desktop@11.0.13/EventDispatchThread.java:203)
at java.awt.EventDispatchThread.pumpEventsForFilter(java.desktop@11.0.13/EventDispatchThread.java:124)
at java.awt.EventDispatchThread.pumpEventsForFilter(java.desktop@11.0.13/EventDispatchThread.java:117)
at java.awt.WaitDispatchSupport$2.run(java.desktop@11.0.13/WaitDispatchSupport.java:190)
at java.awt.WaitDispatchSupport$4.run(java.desktop@11.0.13/WaitDispatchSupport.java:235)
at java.awt.WaitDispatchSupport$4.run(java.desktop@11.0.13/WaitDispatchSupport.java:233)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.awt.WaitDispatchSupport.enter(java.desktop@11.0.13/WaitDispatchSupport.java:233)
at java.awt.Dialog.show(java.desktop@11.0.13/Dialog.java:1070)
at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl$MyDialog.show(DialogWrapperPeerImpl.java:701)
at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl.show(DialogWrapperPeerImpl.java:437)
at com.intellij.openapi.ui.DialogWrapper.doShow(DialogWrapper.java:1671)
at com.intellij.openapi.ui.DialogWrapper.show(DialogWrapper.java:1629)
at com.intellij.execution.actions.EditRunConfigurationsAction.actionPerformed(EditRunConfigurationsAction.java:30)
at com.intellij.openapi.actionSystem.ex.ActionUtil.lambda$performActionDumbAwareWithCallbacks$4(ActionUtil.java:244)
at com.intellij.openapi.actionSystem.ex.ActionUtil$$Lambda$3739/0x000000080281dc40.run(Unknown Source)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:265)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks(ActionUtil.java:244)
at com.intellij.ui.popup.ActionPopupStep.performAction(ActionPopupStep.java:253)
at com.intellij.ui.popup.ActionPopupStep.performAction(ActionPopupStep.java:243)
at com.intellij.ui.popup.ActionPopupStep.lambda$onChosen$2(ActionPopupStep.java:229)
at com.intellij.ui.popup.ActionPopupStep$$Lambda$8343/0x0000000804a5c840.run(Unknown Source)
at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:94)
at com.intellij.ui.popup.AbstractPopup.lambda$dispose$18(AbstractPopup.java:1511)
at com.intellij.ui.popup.AbstractPopup$$Lambda$7580/0x00000008047cf040.run(Unknown Source)
at com.intellij.util.ui.EdtInvocationManager.invokeLaterIfNeeded(EdtInvocationManager.java:101)
at com.intellij.ide.IdeEventQueue.ifFocusEventsInTheQueue(IdeEventQueue.java:186)
at com.intellij.ide.IdeEventQueue.executeWhenAllFocusEventsLeftTheQueue(IdeEventQueue.java:140)
at com.intellij.openapi.wm.impl.FocusManagerImpl.doWhenFocusSettlesDown(FocusManagerImpl.java:175)
at com.intellij.openapi.wm.impl.IdeFocusManagerImpl.doWhenFocusSettlesDown(IdeFocusManagerImpl.java:36)
at com.intellij.ui.popup.AbstractPopup.dispose(AbstractPopup.java:1508)
at com.intellij.ui.popup.WizardPopup.dispose(WizardPopup.java:164)
at com.intellij.ui.popup.list.ListPopupImpl.dispose(ListPopupImpl.java:326)
at com.intellij.ui.popup.PopupFactoryImpl$ActionGroupPopup.dispose(PopupFactoryImpl.java:271)
at com.intellij.openapi.util.ObjectTree.runWithTrace(ObjectTree.java:136)
at com.intellij.openapi.util.ObjectTree.executeAll(ObjectTree.java:166)
at com.intellij.openapi.util.Disposer.dispose(Disposer.java:169)
at com.intellij.openapi.util.Disposer.dispose(Disposer.java:157)
at com.intellij.ui.popup.WizardPopup.disposeAllParents(WizardPopup.java:268)
at com.intellij.ui.popup.list.ListPopupImpl.handleNextStep(ListPopupImpl.java:433)
at com.intellij.ui.popup.list.ListPopupImpl._handleSelect(ListPopupImpl.java:405)
at com.intellij.ui.popup.list.ListPopupImpl.handleSelect(ListPopupImpl.java:361)
at com.intellij.ui.popup.PopupFactoryImpl$ActionGroupPopup.handleSelect(PopupFactoryImpl.java:288)
at com.intellij.ui.popup.list.ListPopupImpl$MyMouseListener.mouseReleased(ListPopupImpl.java:618)
at java.awt.AWTEventMulticaster.mouseReleased(java.desktop@11.0.13/AWTEventMulticaster.java:298)
at java.awt.Component.processMouseEvent(java.desktop@11.0.13/Component.java:6654)
at javax.swing.JComponent.processMouseEvent(java.desktop@11.0.13/JComponent.java:3345)
at com.intellij.ui.popup.list.ListPopupImpl$MyList.processMouseEvent(ListPopupImpl.java:695)
at java.awt.Component.processEvent(java.desktop@11.0.13/Component.java:6419)
at java.awt.Container.processEvent(java.desktop@11.0.13/Container.java:2263)
at java.awt.Component.dispatchEventImpl(java.desktop@11.0.13/Component.java:5029)
at java.awt.Container.dispatchEventImpl(java.desktop@11.0.13/Container.java:2321)
at java.awt.Component.dispatchEvent(java.desktop@11.0.13/Component.java:4861)
at java.awt.LightweightDispatcher.retargetMouseEvent(java.desktop@11.0.13/Container.java:4918)
at java.awt.LightweightDispatcher.processMouseEvent(java.desktop@11.0.13/Container.java:4547)
at java.awt.LightweightDispatcher.dispatchEvent(java.desktop@11.0.13/Container.java:4488)
at java.awt.Container.dispatchEventImpl(java.desktop@11.0.13/Container.java:2307)
at java.awt.Window.dispatchEventImpl(java.desktop@11.0.13/Window.java:2790)
at java.awt.Component.dispatchEvent(java.desktop@11.0.13/Component.java:4861)
at java.awt.EventQueue.dispatchEventImpl(java.desktop@11.0.13/EventQueue.java:778)
at java.awt.EventQueue$4.run(java.desktop@11.0.13/EventQueue.java:727)
at java.awt.EventQueue$4.run(java.desktop@11.0.13/EventQueue.java:721)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@11.0.13/ProtectionDomain.java:85)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@11.0.13/ProtectionDomain.java:95)
at java.awt.EventQueue$5.run(java.desktop@11.0.13/EventQueue.java:751)
at java.awt.EventQueue$5.run(java.desktop@11.0.13/EventQueue.java:749)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(java.base@11.0.13/ProtectionDomain.java:85)
at java.awt.EventQueue.dispatchEvent(java.desktop@11.0.13/EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
at com.intellij.ide.IdeEventQueue$$Lambda$557/0x00000008005db040.compute(Unknown Source)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
at com.intellij.ide.IdeEventQueue$$Lambda$555/0x00000008005d9c40.run(Unknown Source)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
at java.awt.EventDispatchThread.pumpOneEventForFilters(java.desktop@11.0.13/EventDispatchThread.java:203)
at java.awt.EventDispatchThread.pumpEventsForFilter(java.desktop@11.0.13/EventDispatchThread.java:124)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(java.desktop@11.0.13/EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(java.desktop@11.0.13/EventDispatchThread.java:109)
at java.awt.EventDispatchThread.pumpEvents(java.desktop@11.0.13/EventDispatchThread.java:101)
at java.awt.EventDispatchThread.run(java.desktop@11.0.13/EventDispatchThread.java:90)
Locked ownable synchronizers:
- <0x0000000674216958> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
- <0x00000006742195c0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
- <0x000000067440ca38> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
"Java2D Queue Flusher" #18 daemon prio=10 os_prio=31 cpu=2507.85ms elapsed=1146.11s tid=0x00007fdd838a4000 nid=0x12c0b in Object.wait() [0x000070000e3cd000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at sun.java2d.opengl.OGLRenderQueue$QueueFlusher.run(java.desktop@11.0.13/OGLRenderQueue.java:228)
- waiting to re-lock in wait() <0x000000060ca43908> (a sun.java2d.opengl.OGLRenderQueue$QueueFlusher)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"Java2D Disposer" #19 daemon prio=10 os_prio=31 cpu=17.79ms elapsed=1146.06s tid=0x00007fdd63144000 nid=0xe603 in Object.wait() [0x000070000e4d0000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:155)
- waiting to re-lock in wait() <0x000000060ca43b08> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:176)
at sun.java2d.Disposer.run(java.desktop@11.0.13/Disposer.java:144)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"AWTThreading pool-1-thread-1" #20 daemon prio=5 os_prio=31 cpu=45.56ms elapsed=1145.78s tid=0x00007fdd53136000 nid=0x10803 waiting on condition [0x000070000f602000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d8e0998> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.park(java.base@11.0.13/LockSupport.java:194)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.take(java.base@11.0.13/SynchronousQueue.java:920)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"JobScheduler FJ pool 3/15" #22 daemon prio=4 os_prio=31 cpu=8946.16ms elapsed=1145.31s tid=0x00007fdd852b5000 nid=0x15803 waiting on condition [0x000070000f706000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060ca22600> (a java.util.concurrent.ForkJoinPool)
at java.util.concurrent.locks.LockSupport.parkUntil(java.base@11.0.13/LockSupport.java:275)
at java.util.concurrent.ForkJoinPool.runWorker(java.base@11.0.13/ForkJoinPool.java:1619)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base@11.0.13/ForkJoinWorkerThread.java:183)
Locked ownable synchronizers:
- None
"Periodic tasks thread" #23 daemon prio=6 os_prio=31 cpu=1303.47ms elapsed=1145.30s tid=0x00007fdd3300e000 nid=0x15a03 waiting on condition [0x000070000f809000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d90db58> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@11.0.13/AbstractQueuedSynchronizer.java:2123)
at java.util.concurrent.DelayQueue.take(java.base@11.0.13/DelayQueue.java:229)
at com.intellij.util.concurrency.AppDelayQueue.lambda$new$0(AppDelayQueue.java:26)
at com.intellij.util.concurrency.AppDelayQueue$$Lambda$273/0x0000000800307040.run(Unknown Source)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"process reaper" #25 daemon prio=10 os_prio=31 cpu=0.88ms elapsed=1145.29s tid=0x00007fdd431fb000 nid=0x1f803 runnable [0x000070000f933000]
java.lang.Thread.State: RUNNABLE
at java.lang.ProcessHandleImpl.waitForProcessExit0(java.base@11.0.13/Native Method)
at java.lang.ProcessHandleImpl$1.run(java.base@11.0.13/ProcessHandleImpl.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- <0x000000060d967fe0> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"JobScheduler FJ pool 7/15" #30 daemon prio=4 os_prio=31 cpu=11280.30ms elapsed=1145.15s tid=0x00007fdd23008800 nid=0x16403 waiting on condition [0x000070000fd3f000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060ca22600> (a java.util.concurrent.ForkJoinPool)
at java.util.concurrent.locks.LockSupport.park(java.base@11.0.13/LockSupport.java:194)
at java.util.concurrent.ForkJoinPool.runWorker(java.base@11.0.13/ForkJoinPool.java:1628)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base@11.0.13/ForkJoinWorkerThread.java:183)
Locked ownable synchronizers:
- None
"Netty Builtin Server 1" #32 daemon prio=4 os_prio=31 cpu=50.71ms elapsed=1145.14s tid=0x00007fdd53450800 nid=0x1f103 runnable [0x000070000ff45000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.KQueue.poll(java.base@11.0.13/Native Method)
at sun.nio.ch.KQueueSelectorImpl.doSelect(java.base@11.0.13/KQueueSelectorImpl.java:122)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@11.0.13/SelectorImpl.java:124)
- locked <0x000000060d886cd0> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x000000060d886c70> (a sun.nio.ch.KQueueSelectorImpl)
at sun.nio.ch.SelectorImpl.select(java.base@11.0.13/SelectorImpl.java:136)
at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:814)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"JobScheduler FJ pool 11/15" #34 daemon prio=4 os_prio=31 cpu=16500.08ms elapsed=1145.12s tid=0x00007fdd26010000 nid=0x16903 waiting on condition [0x000070001014b000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060ca22600> (a java.util.concurrent.ForkJoinPool)
at java.util.concurrent.locks.LockSupport.park(java.base@11.0.13/LockSupport.java:194)
at java.util.concurrent.ForkJoinPool.runWorker(java.base@11.0.13/ForkJoinPool.java:1628)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base@11.0.13/ForkJoinWorkerThread.java:183)
Locked ownable synchronizers:
- None
"JobScheduler FJ pool 12/15" #36 daemon prio=4 os_prio=31 cpu=14393.98ms elapsed=1145.12s tid=0x00007fdd852a6800 nid=0x16c03 waiting on condition [0x0000700010351000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060ca22600> (a java.util.concurrent.ForkJoinPool)
at java.util.concurrent.locks.LockSupport.park(java.base@11.0.13/LockSupport.java:194)
at java.util.concurrent.ForkJoinPool.runWorker(java.base@11.0.13/ForkJoinPool.java:1628)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base@11.0.13/ForkJoinWorkerThread.java:183)
Locked ownable synchronizers:
- None
"JobScheduler FJ pool 14/15" #38 daemon prio=4 os_prio=31 cpu=17360.71ms elapsed=1145.12s tid=0x00007fdd33012000 nid=0x1e303 waiting on condition [0x0000700010557000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060ca22600> (a java.util.concurrent.ForkJoinPool)
at java.util.concurrent.locks.LockSupport.park(java.base@11.0.13/LockSupport.java:194)
at java.util.concurrent.ForkJoinPool.runWorker(java.base@11.0.13/ForkJoinPool.java:1628)
at java.util.concurrent.ForkJoinWorkerThread.run(java.base@11.0.13/ForkJoinWorkerThread.java:183)
Locked ownable synchronizers:
- None
"Netty Builtin Server 2" #39 prio=4 os_prio=31 cpu=5.28ms elapsed=1144.06s tid=0x00007fdd8413a000 nid=0x1db03 runnable [0x0000700010963000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.KQueue.poll(java.base@11.0.13/Native Method)
at sun.nio.ch.KQueueSelectorImpl.doSelect(java.base@11.0.13/KQueueSelectorImpl.java:122)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@11.0.13/SelectorImpl.java:124)
- locked <0x000000060eabd830> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x000000060eabe858> (a sun.nio.ch.KQueueSelectorImpl)
at sun.nio.ch.SelectorImpl.select(java.base@11.0.13/SelectorImpl.java:136)
at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:814)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"ektorp-idle-connection-monitor-thread-1" #45 daemon prio=5 os_prio=31 cpu=4.77ms elapsed=1142.96s tid=0x00007fdd53495000 nid=0x1d003 waiting on condition [0x0000700010f75000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x00000006134dc4b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@11.0.13/AbstractQueuedSynchronizer.java:2123)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@11.0.13/ScheduledThreadPoolExecutor.java:1182)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(java.base@11.0.13/ScheduledThreadPoolExecutor.java:899)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1054)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"fsnotifier" #49 prio=4 os_prio=31 cpu=0.32ms elapsed=1142.56s tid=0x00007fdd8525b800 nid=0x1c603 in Object.wait() [0x000070001137f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <0x00000006134b0420> (a java.lang.ProcessImpl)
at java.lang.Object.wait(java.base@11.0.13/Object.java:328)
at java.lang.ProcessImpl.waitFor(java.base@11.0.13/ProcessImpl.java:495)
- waiting to re-lock in wait() <0x00000006134b0420> (a java.lang.ProcessImpl)
at com.intellij.execution.process.ProcessWaitFor.lambda$new$0(ProcessWaitFor.java:28)
at com.intellij.execution.process.ProcessWaitFor$$Lambda$1091/0x0000000800beec40.run(Unknown Source)
at com.intellij.util.ConcurrencyUtil.runUnderThreadName(ConcurrencyUtil.java:213)
at com.intellij.execution.process.ProcessWaitFor.lambda$new$1(ProcessWaitFor.java:23)
at com.intellij.execution.process.ProcessWaitFor$$Lambda$1090/0x0000000800bee840.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.13/Executors.java:515)
at java.util.concurrent.FutureTask.run(java.base@11.0.13/FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- <0x00000006134b06a0> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"BaseDataReader: output stream of fsnotifier" #50 prio=4 os_prio=31 cpu=207.45ms elapsed=1142.55s tid=0x00007fdd53675000 nid=0x1c403 runnable [0x0000700011482000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(java.base@11.0.13/Native Method)
at java.io.FileInputStream.read(java.base@11.0.13/FileInputStream.java:279)
at java.io.BufferedInputStream.read1(java.base@11.0.13/BufferedInputStream.java:290)
at java.io.BufferedInputStream.read(java.base@11.0.13/BufferedInputStream.java:351)
- locked <0x0000000615dedc20> (a java.lang.ProcessImpl$ProcessPipeInputStream)
at sun.nio.cs.StreamDecoder.readBytes(java.base@11.0.13/StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(java.base@11.0.13/StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(java.base@11.0.13/StreamDecoder.java:178)
- locked <0x0000000615dedc90> (a com.intellij.util.io.BaseInputStreamReader)
at java.io.InputStreamReader.read(java.base@11.0.13/InputStreamReader.java:181)
at java.io.Reader.read(java.base@11.0.13/Reader.java:229)
at com.intellij.util.io.BaseOutputReader.readAvailableBlocking(BaseOutputReader.java:133)
at com.intellij.util.io.BaseDataReader.readAvailable(BaseDataReader.java:74)
at com.intellij.util.io.BaseDataReader.doRun(BaseDataReader.java:155)
at com.intellij.util.io.BaseDataReader$$Lambda$1093/0x0000000800bee440.run(Unknown Source)
at com.intellij.util.ConcurrencyUtil.runUnderThreadName(ConcurrencyUtil.java:213)
at com.intellij.util.io.BaseDataReader.lambda$start$0(BaseDataReader.java:50)
at com.intellij.util.io.BaseDataReader$$Lambda$1092/0x0000000800bee040.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.13/Executors.java:515)
at java.util.concurrent.FutureTask.run(java.base@11.0.13/FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- <0x0000000615df1da0> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"BaseDataReader: error stream of fsnotifier" #51 prio=4 os_prio=31 cpu=0.17ms elapsed=1142.55s tid=0x00007fdd2602b000 nid=0x1c103 runnable [0x0000700011585000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(java.base@11.0.13/Native Method)
at java.io.FileInputStream.read(java.base@11.0.13/Unknown Source)
at java.io.BufferedInputStream.read1(java.base@11.0.13/BufferedInputStream.java:290)
at java.io.BufferedInputStream.read(java.base@11.0.13/BufferedInputStream.java:351)
- locked <0x0000000613402358> (a java.lang.ProcessImpl$ProcessPipeInputStream)
at sun.nio.cs.StreamDecoder.readBytes(java.base@11.0.13/StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(java.base@11.0.13/StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(java.base@11.0.13/StreamDecoder.java:178)
- locked <0x00000006134023e0> (a com.intellij.util.io.BaseInputStreamReader)
at java.io.InputStreamReader.read(java.base@11.0.13/InputStreamReader.java:181)
at java.io.Reader.read(java.base@11.0.13/Reader.java:229)
at com.intellij.util.io.BaseOutputReader.readAvailableBlocking(BaseOutputReader.java:133)
at com.intellij.util.io.BaseDataReader.readAvailable(BaseDataReader.java:74)
at com.intellij.util.io.BaseDataReader.doRun(BaseDataReader.java:155)
at com.intellij.util.io.BaseDataReader$$Lambda$1093/0x0000000800bee440.run(Unknown Source)
at com.intellij.util.ConcurrencyUtil.runUnderThreadName(ConcurrencyUtil.java:213)
at com.intellij.util.io.BaseDataReader.lambda$start$0(BaseDataReader.java:50)
at com.intellij.util.io.BaseDataReader$$Lambda$1092/0x0000000800bee040.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.13/Executors.java:515)
at java.util.concurrent.FutureTask.run(java.base@11.0.13/FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- <0x00000006134065d0> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"TimerQueue" #54 daemon prio=5 os_prio=31 cpu=529.97ms elapsed=1142.46s tid=0x00007fdd53152000 nid=0x15563 waiting on condition [0x000070001178d000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x0000000615d93a38> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@11.0.13/AbstractQueuedSynchronizer.java:2123)
at java.util.concurrent.DelayQueue.take(java.base@11.0.13/DelayQueue.java:229)
at javax.swing.TimerQueue.run(java.desktop@11.0.13/TimerQueue.java:171)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- <0x0000000613b21420> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
"DestroyJavaVM" #56 prio=5 os_prio=31 cpu=5652.98ms elapsed=1138.11s tid=0x00007fdd535fd800 nid=0x1c03 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-1" #57 daemon prio=4 os_prio=31 cpu=63.17ms elapsed=1133.39s tid=0x00007fdd84382800 nid=0x17407 waiting on condition [0x000070000de35000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-2" #58 daemon prio=4 os_prio=31 cpu=229.50ms elapsed=1133.39s tid=0x00007fdd84383800 nid=0x17507 waiting on condition [0x0000700010d6f000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-3" #59 daemon prio=4 os_prio=31 cpu=501.74ms elapsed=1133.39s tid=0x00007fdd634a8800 nid=0x1870b waiting on condition [0x0000700011993000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-4" #60 daemon prio=4 os_prio=31 cpu=55.23ms elapsed=1133.39s tid=0x00007fdd6349c800 nid=0x1bc03 waiting on condition [0x0000700011a96000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-5" #61 daemon prio=4 os_prio=31 cpu=517.98ms elapsed=1133.39s tid=0x00007fdd6349d800 nid=0x18a03 waiting on condition [0x0000700011b99000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-6" #62 daemon prio=4 os_prio=31 cpu=84.87ms elapsed=1133.39s tid=0x00007fdd43570800 nid=0x1b803 waiting on condition [0x0000700011c9c000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-7" #63 daemon prio=4 os_prio=31 cpu=38.97ms elapsed=1133.39s tid=0x00007fdd83ac3000 nid=0x1b603 waiting on condition [0x0000700011d9f000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-8" #64 daemon prio=4 os_prio=31 cpu=138.80ms elapsed=1133.38s tid=0x00007fdd33884800 nid=0x1b403 waiting on condition [0x0000700011ea2000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-9" #65 daemon prio=4 os_prio=31 cpu=42.29ms elapsed=1133.38s tid=0x00007fdd33840800 nid=0x1b203 waiting on condition [0x0000700011fa5000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-10" #66 daemon prio=4 os_prio=31 cpu=40.93ms elapsed=1133.38s tid=0x00007fdd84466800 nid=0x19003 waiting on condition [0x00007000120a8000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-11" #67 daemon prio=4 os_prio=31 cpu=45.72ms elapsed=1133.38s tid=0x00007fdd23020000 nid=0x19203 waiting on condition [0x00007000121ab000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-12" #68 daemon prio=4 os_prio=31 cpu=171.32ms elapsed=1133.38s tid=0x00007fdd63063000 nid=0x1ad03 waiting on condition [0x00007000122ae000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"kotlinx.coroutines.DefaultExecutor" #71 daemon prio=4 os_prio=31 cpu=11.43ms elapsed=1133.22s tid=0x00007fdd84664000 nid=0x19703 waiting on condition [0x00007000124b4000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000061ec00558> (a kotlinx.coroutines.DefaultExecutor)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at kotlinx.coroutines.DefaultExecutor.run(DefaultExecutor.kt:82)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"ApplicationImpl pooled thread 12" #83 prio=4 os_prio=31 cpu=40040.01ms elapsed=1130.25s tid=0x00007fdd33827800 nid=0x20977 waiting on condition [0x0000700013201000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d93ad88> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:462)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(java.base@11.0.13/SynchronousQueue.java:937)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1053)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-13" #106 daemon prio=4 os_prio=31 cpu=43.82ms elapsed=1113.56s tid=0x00007fdce7313000 nid=0x23603 waiting on condition [0x0000700012bf0000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-14" #107 daemon prio=4 os_prio=31 cpu=44.57ms elapsed=1113.56s tid=0x00007fdd8575d000 nid=0x23703 waiting on condition [0x0000700012cf3000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-15" #108 daemon prio=4 os_prio=31 cpu=143.72ms elapsed=1113.56s tid=0x00007fdd6367e000 nid=0x28203 waiting on condition [0x0000700014335000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"DefaultDispatcher-worker-16" #109 daemon prio=4 os_prio=31 cpu=39.56ms elapsed=1113.56s tid=0x00007fdd63222000 nid=0x28003 waiting on condition [0x0000700014438000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:357)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.park(CoroutineScheduler.kt:795)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.tryPark(CoroutineScheduler.kt:740)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:711)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Locked ownable synchronizers:
- None
"Netty Builtin Server 3" #117 daemon prio=4 os_prio=31 cpu=19.94ms elapsed=1110.43s tid=0x00007fdce7135000 nid=0x27403 runnable [0x0000700014b4d000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.KQueue.poll(java.base@11.0.13/Native Method)
at sun.nio.ch.KQueueSelectorImpl.doSelect(java.base@11.0.13/KQueueSelectorImpl.java:122)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@11.0.13/SelectorImpl.java:124)
- locked <0x000000060da56c60> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x000000060da57c88> (a sun.nio.ch.KQueueSelectorImpl)
at sun.nio.ch.SelectorImpl.select(java.base@11.0.13/SelectorImpl.java:141)
at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:68)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:810)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"Batik CleanerThread" #172 daemon prio=6 os_prio=31 cpu=0.13ms elapsed=1024.88s tid=0x00007fdd53580800 nid=0x25e0b in Object.wait() [0x0000700010a66000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:155)
- waiting to re-lock in wait() <0x0000000628123a60> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@11.0.13/ReferenceQueue.java:176)
at org.apache.batik.util.CleanerThread.run(CleanerThread.java:106)
Locked ownable synchronizers:
- None
"ApplicationImpl pooled thread 40" #232 prio=4 os_prio=31 cpu=7164.26ms elapsed=715.11s tid=0x00007fdd83dde000 nid=0x1781f waiting on condition [0x000070000f90b000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d93ad88> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:462)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(java.base@11.0.13/SynchronousQueue.java:937)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1053)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"JFR Recorder Thread" #248 daemon prio=5 os_prio=31 cpu=14.70ms elapsed=627.97s tid=0x00007fdd31d7e000 nid=0x293bf waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"JFR Periodic Tasks" #250 daemon prio=4 os_prio=31 cpu=254.90ms elapsed=627.02s tid=0x00007fdd436ed000 nid=0x29e0b in Object.wait() [0x0000700012ef9000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at jdk.jfr.internal.PlatformRecorder.takeNap(jdk.jfr@11.0.13/PlatformRecorder.java:448)
- waiting to re-lock in wait() <0x0000000676ba8bc0> (a java.lang.Object)
at jdk.jfr.internal.PlatformRecorder.periodicTask(jdk.jfr@11.0.13/PlatformRecorder.java:441)
at jdk.jfr.internal.PlatformRecorder.lambda$startDiskMonitor$1(jdk.jfr@11.0.13/PlatformRecorder.java:386)
at jdk.jfr.internal.PlatformRecorder$$Lambda$8463/0x0000000804afd440.run(jdk.jfr@11.0.13/Unknown Source)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"JFR Recording Scheduler" #253 daemon prio=4 os_prio=31 cpu=0.15ms elapsed=627.01s tid=0x00007fdd5350d800 nid=0x29a1b in Object.wait() [0x00007000130ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <0x0000000676ba2e98> (a java.util.TaskQueue)
at java.lang.Object.wait(java.base@11.0.13/Object.java:328)
at java.util.TimerThread.mainLoop(java.base@11.0.13/Timer.java:527)
- waiting to re-lock in wait() <0x0000000676ba2e98> (a java.util.TaskQueue)
at java.util.TimerThread.run(java.base@11.0.13/Timer.java:506)
Locked ownable synchronizers:
- None
"ApplicationImpl pooled thread 45" #255 prio=4 os_prio=31 cpu=154.04ms elapsed=556.39s tid=0x00007fdd83cb5000 nid=0x1d643 in Object.wait() [0x000070000fc3a000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11.0.13/Native Method)
- waiting on <no object reference available>
at java.lang.Object.wait(java.base@11.0.13/Object.java:328)
at java.awt.EventQueue.invokeAndWait(java.desktop@11.0.13/EventQueue.java:1367)
- waiting to re-lock in wait() <0x0000000685ef3c40> (a java.awt.EventQueue$1AWTInvocationLock)
at java.awt.EventQueue.invokeAndWait(java.desktop@11.0.13/EventQueue.java:1348)
at javax.swing.SwingUtilities.invokeAndWait(java.desktop@11.0.13/SwingUtilities.java:1480)
at com.intellij.internal.statistic.collectors.fus.ui.UiInfoUsageCollector.addScreenScale(UiInfoUsageCollector.java:167)
at com.intellij.internal.statistic.collectors.fus.ui.UiInfoUsageCollector.getDescriptors(UiInfoUsageCollector.java:113)
at com.intellij.internal.statistic.collectors.fus.ui.UiInfoUsageCollector.getMetrics(UiInfoUsageCollector.java:80)
at com.intellij.internal.statistic.service.fus.collectors.FUStateUsagesLogger.logApplicationStates(FUStateUsagesLogger.java:64)
- locked <0x000000062b078df0> (a java.lang.Object)
at com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler.lambda$runStatesLogging$0(StatisticsStateCollectorsScheduler.java:39)
at com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler$$Lambda$801/0x0000000800824440.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.13/Executors.java:515)
at java.util.concurrent.FutureTask.runAndReset(java.base@11.0.13/FutureTask.java:305)
at com.intellij.util.concurrency.SchedulingWrapper$MyScheduledFutureTask.run(SchedulingWrapper.java:223)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- <0x0000000685e95180> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"ApplicationImpl pooled thread 50" #262 prio=4 os_prio=31 cpu=333.20ms elapsed=520.36s tid=0x00007fdce7334000 nid=0x24a4b waiting on condition [0x000070001117a000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d93ad88> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:462)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(java.base@11.0.13/SynchronousQueue.java:937)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1053)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"ApplicationImpl pooled thread 55" #267 prio=4 os_prio=31 cpu=93.09ms elapsed=226.38s tid=0x00007fdd23052800 nid=0x20723 waiting on condition [0x000070000fe41000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d93ad88> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:462)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(java.base@11.0.13/SynchronousQueue.java:937)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1053)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"ApplicationImpl pooled thread 56" #270 prio=4 os_prio=31 cpu=0.58ms elapsed=16.08s tid=0x00007fdd8482b000 nid=0x9d07 waiting on condition [0x000070000c2f5000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d93ad88> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:462)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(java.base@11.0.13/SynchronousQueue.java:937)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1053)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"ApplicationImpl pooled thread 57" #271 prio=4 os_prio=31 cpu=0.34ms elapsed=9.12s tid=0x00007fdd2484d800 nid=0x624f waiting on condition [0x000070000dbae000]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11.0.13/Native Method)
- parking to wait for <0x000000060d93ad88> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.13/LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(java.base@11.0.13/SynchronousQueue.java:462)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(java.base@11.0.13/SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(java.base@11.0.13/SynchronousQueue.java:937)
at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@11.0.13/ThreadPoolExecutor.java:1053)
at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.13/ThreadPoolExecutor.java:1114)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.13/ThreadPoolExecutor.java:628)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:668)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(java.base@11.0.13/Executors.java:665)
at java.security.AccessController.doPrivileged(java.base@11.0.13/Native Method)
at java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(java.base@11.0.13/Executors.java:665)
at java.lang.Thread.run(java.base@11.0.13/Thread.java:829)
Locked ownable synchronizers:
- None
"Attach Listener" #272 daemon prio=9 os_prio=31 cpu=0.76ms elapsed=1.59s tid=0x00007fdd31a79800 nid=0x5f0b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"VM Thread" os_prio=31 cpu=5802.39ms elapsed=1146.60s tid=0x00007fdd63019000 nid=0x3a03 runnable
"GC Thread#0" os_prio=31 cpu=3490.22ms elapsed=1146.62s tid=0x00007fdd84826000 nid=0x4a03 runnable
"GC Thread#1" os_prio=31 cpu=3464.22ms elapsed=1145.90s tid=0x00007fdd83631800 nid=0xed07 runnable
"GC Thread#2" os_prio=31 cpu=3470.68ms elapsed=1145.90s tid=0x00007fdd838bf800 nid=0xef03 runnable
"GC Thread#3" os_prio=31 cpu=3452.74ms elapsed=1145.90s tid=0x00007fdd838c0800 nid=0xf003 runnable
"GC Thread#4" os_prio=31 cpu=3460.34ms elapsed=1145.90s tid=0x00007fdd838c5800 nid=0x11603 runnable
"GC Thread#5" os_prio=31 cpu=3541.64ms elapsed=1145.90s tid=0x00007fdd838c6000 nid=0x11403 runnable
"GC Thread#6" os_prio=31 cpu=3460.37ms elapsed=1145.90s tid=0x00007fdd838c7000 nid=0xf203 runnable
"GC Thread#7" os_prio=31 cpu=3462.20ms elapsed=1145.90s tid=0x00007fdd838c7800 nid=0xf403 runnable
"GC Thread#8" os_prio=31 cpu=3473.97ms elapsed=1145.90s tid=0x00007fdd84092800 nid=0xf603 runnable
"GC Thread#9" os_prio=31 cpu=3478.22ms elapsed=1145.90s tid=0x00007fdd838c8800 nid=0xf803 runnable
"GC Thread#10" os_prio=31 cpu=3473.38ms elapsed=1145.90s tid=0x00007fdd838c9000 nid=0xf903 runnable
"GC Thread#11" os_prio=31 cpu=3515.53ms elapsed=1145.90s tid=0x00007fdd84071800 nid=0xfa03 runnable
"GC Thread#12" os_prio=31 cpu=3494.82ms elapsed=1145.90s tid=0x00007fdd840fc000 nid=0x11003 runnable
"G1 Main Marker" os_prio=31 cpu=25.32ms elapsed=1146.62s tid=0x00007fdd85048000 nid=0x3503 runnable
"G1 Conc#0" os_prio=31 cpu=7713.43ms elapsed=1146.62s tid=0x00007fdd85048800 nid=0x3603 runnable
"G1 Conc#1" os_prio=31 cpu=7701.16ms elapsed=1145.86s tid=0x00007fdd838cc800 nid=0x10e03 runnable
"G1 Conc#2" os_prio=31 cpu=7692.32ms elapsed=1145.86s tid=0x00007fdd2600c000 nid=0x10b03 runnable
"G1 Refine#0" os_prio=31 cpu=456.32ms elapsed=1146.61s tid=0x00007fdd8300f800 nid=0x3703 runnable
"G1 Refine#1" os_prio=31 cpu=91.16ms elapsed=1145.86s tid=0x00007fdd63149000 nid=0x10d03 runnable
"G1 Refine#2" os_prio=31 cpu=58.57ms elapsed=1145.86s tid=0x00007fdd431e8000 nid=0x10a03 runnable
"G1 Refine#3" os_prio=31 cpu=33.76ms elapsed=1144.12s tid=0x00007fdd23813000 nid=0x1e203 runnable
"G1 Refine#4" os_prio=31 cpu=28.00ms elapsed=1144.12s tid=0x00007fdd2400a000 nid=0x1e003 runnable
"G1 Refine#5" os_prio=31 cpu=20.25ms elapsed=1144.12s tid=0x00007fdd23013800 nid=0x1de03 runnable
"G1 Refine#6" os_prio=31 cpu=13.29ms elapsed=1142.37s tid=0x00007fdce70df800 nid=0x1043f runnable
"G1 Refine#7" os_prio=31 cpu=10.45ms elapsed=1132.60s tid=0x00007fdd2483f000 nid=0x19f67 runnable
"G1 Refine#8" os_prio=31 cpu=11.47ms elapsed=1132.60s tid=0x00007fdd23858000 nid=0x1a703 runnable
"G1 Refine#9" os_prio=31 cpu=9.03ms elapsed=1132.60s tid=0x00007fdd23078800 nid=0x1a103 runnable
"G1 Refine#10" os_prio=31 cpu=6.27ms elapsed=1132.60s tid=0x00007fdd3305b000 nid=0x1a403 runnable
"G1 Refine#11" os_prio=31 cpu=6.20ms elapsed=1132.60s tid=0x00007fdd24037800 nid=0x1a203 runnable
"G1 Refine#12" os_prio=31 cpu=5.10ms elapsed=1129.63s tid=0x00007fdd240b3800 nid=0x2215f runnable
"G1 Young RemSet Sampling" os_prio=31 cpu=284.44ms elapsed=1146.61s tid=0x00007fdd83809800 nid=0x4503 runnable
"VM Periodic Task Thread" os_prio=31 cpu=422.50ms elapsed=1146.51s tid=0x00007fdd83009800 nid=0x5d03 waiting on condition
JNI global refs: 431, weak refs: 830
Add explicit menu action for migration
Incorrect grammar in notice about internal api
The last sentence is not required and is grammatically incorrect. Let's drop it please.
1.6.4
released 1st October 2021
Client
Ktor IOS client sometimes deadlocks if Logging is installed
If the Logging plugin is installed the Ktor client deadlocks/blocks sometimes after BODY START
is printed to the console.
The response is still getting returned back to the calling function, but any future requests will block.
It doesn't happen every time, but it is reasonably easy to reproduce it with the attached Sample app.
Fix Flaky BodyProgressTest.testSendChannel
Fix Flaky Timeout Priority Test
Bearer Authentication: Queue requests until refresh of tokens is completed
Hi, I'm using Ktor 1.6.4 in a Kotlin Multiplatform project together with the Bearer Authentication feature.
We are logging the user out when the refresh of the token wasn't successful. Our Open ID Connect server responds with a 400 when the refresh token was used before for a refresh. So when there are multiple requests running in parallel the first refresh is successful but the other request already responds with a 401 and the Auth feature tries to refresh with the same refresh token this leads to a 400 error.
Is there something we can do to queue requests or is this the expected behaviour?
install(Auth) {
bearer {
loadTokens {
val tokenData = getTokenDataInteractor.execute() // Get tokens from storage
if (tokenData.status == SUCCESS && tokenData.data?.accessToken != null) {
BearerTokens(tokenData.data.accessToken, tokenData.data.refreshToken ?: "")
} else {
null
}
}
refreshTokens {
val tokenData = refreshTokenInteractor.execute() // Fetches and stores new token
if (tokenData.status == SUCCESS && tokenData.data?.accessToken != null) {
BearerTokens(tokenData.data.accessToken, tokenData.data.refreshToken ?: "")
} else {
null
}
}
}
}
Does not work with Dropbox (NoTransformationFoundException)
I try to call https://api.dropboxapi.com/2/users/get_current_account but the JSON response can't be parsed.
io.ktor.client.call.NoTransformationFoundException: No transformation found: class io.ktor.utils.io.ByteBufferChannel (Kotlin reflection is not available) -> class com.example.shared.service.DropboxUserInfo (Kotlin reflection is not available)
with response from https://api.dropboxapi.com/2/users/get_current_account:
status: 200 OK
response headers:
Cache-Control: no-cache
, X-Content-Type-Options: nosniff
, X-Frame-Options: SAMEORIGIN
, X-Server-Response-Time: 122
, Content-Type: application/json
, Accept-Encoding: identity,gzip
, Date: Tue, 26 Oct 2021 09:52:32 GMT
, Server: envoy
, Content-Length: 577
, Vary: Accept-Encoding
, X-Dropbox-Response-Origin: far_remote
, X-Dropbox-Request-Id: 1ca6d511848d47d7bee767965a284045
at io.ktor.client.call.HttpClientCall.receive(HttpClientCall.kt:104)
My dependencies:
api("io.ktor:ktor-client-core:${Versions.ktor}")
api("io.ktor:ktor-client-logging:${Versions.ktor}")
api("io.ktor:ktor-client-serialization:${Versions.ktor}")
api("io.ktor:ktor-client-cio:${Versions.ktor}")
api("io.ktor:ktor-client-auth:${Versions.ktor}")
Code:
fun createClient(
oAuthConfig: OAuthConfig,
loadTokenPair: () -> OAuthTokenPair,
saveNewTokenPair: (OAuthTokenPair) -> Unit
): HttpClient {
return HttpClient(CIO) {
install(Auth) {
expectSuccess = false
install(JsonFeature) {
serializer = KotlinxSerializer()
}
bearer {
// ... snip ...
}
}
}
}
@Serializable
data class OAuthTokenPair(
@SerialName("access_token")
val accessToken: String,
/** For a refresh request the refresh token stays the same. */
@SerialName("refresh_token")
val refreshToken: String? = null
)
@Serializable
data class DropboxUserInfo(
val email: String
)
Call:
var currentDropboxTokenPair = loadInititalTokenPair()
val client = OAuthTool.createClient(
oAuthConfig = loadMyConfig(),
loadTokenPair = {
println("Loaded current token: $currentDropboxTokenPair")
return@createClient currentDropboxTokenPair
},
saveNewTokenPair = {
println("New token to save: $it")
currentDropboxTokenPair = it
}
)
val currentUserPath = "https://api.dropboxapi.com/2/users/get_current_account"
val userInfo = client.post<DropboxUserInfo>(currentUserPath)
Fix Flaky CIORequestTest.testTimeoutPriority
Installed Closeable features not closed when closing HttpClient
Hi! I'm writing a custom feature that saves cookies to a file when the installed HttpClient
closes. From reading the HttpClient.close()
function here, it seems that the intention is that the close()
call will cascade to installed Closeable
features; but I discovered that my feature's close()
function is not called due to seemingly another layer of indirection in HttpClientConfig.install()
.
This test below demonstrates the problem:
class FeatureCloseTest {
@Test
fun testFeatureCloseIsCalled() {
val client = HttpClient(MockEngine) {
engine { addHandler { respond("") } }
install(TestFeature)
}
client.close()
assert(client.feature(TestFeature)!!.called) // This fails
}
class TestFeature : Closeable {
var called = false
override fun close() {
called = true
}
companion object : HttpClientFeature<Unit, TestFeature> {
override val key: AttributeKey<TestFeature> = AttributeKey("TestFeature")
override fun install(feature: TestFeature, scope: HttpClient) = Unit
override fun prepare(block: Unit.() -> Unit): TestFeature = TestFeature()
}
}
}
I think this is a bug? I can work around it at the moment to explicitly call my feature's close()
function, but it would be good to get this fixed.
Core
Prohibit Nesting of `install` Blocks for Client and Server Configuration
This code snippet is allowed, but leads to invalid configuration:
val client = HttpClient() {
install(JsonFeature) {
install(Auth) {
// ...
}
}
}
Cyclic dependency issue in latest 2.0 (main branch)
Detecting cycle in external variants for :
io.ktor:ktor-network:main-235:
- io.ktor:ktor-http-cio-jvm:main-235:
- io.ktor:ktor-http-cio:main-235:
- io.ktor:ktor-server-host-common:main-235:
- io.ktor:ktor-server-host-common-kotlinMultiplatform:main-235:
- io.ktor:ktor-server-netty:main-235: com.example:bcf:0.0.1
Dependency resolution has ignored the cycle to produce a result. It is recommended to resolve the cycle by upgrading one or more dependencies.
Cycle Variant Dependency Problem with Latest EAP
Detecting cycle in external variants for :
io.ktor:ktor-network:main-243:
- io.ktor:ktor-http-cio-jvm:main-243:
- io.ktor:ktor-http-cio:main-243:
- io.ktor:ktor-server-host-common:main-243:
- io.ktor:ktor-server-host-common-kotlinMultiplatform:main-243:
- io.ktor:ktor-server-netty:main-243:
- ktor-codesnippets:upload-file-testing-config:unspecified
- io.ktor:ktor-server-netty:main-243:
- io.ktor:ktor-server-host-common-kotlinMultiplatform:main-243:
- io.ktor:ktor-server-host-common:main-243:
- io.ktor:ktor-http-cio:main-243:
Significant performance penalty with socket write() and file read() on JVM
Hi,
It seems that there are performance issues with the current implementation of TCP socket write and also with reading files. Attaching the performance comparison for ktor IO vs regular JVM raw IO:
Files:
--------------------------------------------------------------------
Ktor channel read (128MiB), 20 iterations
Avg: 1239.65ms Min: 1095ms, Max: 1723ms
Raw: 1095, 1104, 1113, 1113, 1113, 1122, 1123, 1126, 1151, 1184, 1249, 1251, 1254, 1254, 1278, 1314, 1351, 1399, 1476, 1723
--------------------------------------------------------------------
Random File Read (128MiB), 20 iterations
Avg: 75.4ms Min: 65ms, Max: 161ms
Raw: 65, 65, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 70, 70, 75, 79, 83, 96, 161
--------------------------------------------------------------------
Stream Read (128MiB), 20 iterations
Avg: 58.5ms Min: 56ms, Max: 69ms
Raw: 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 59, 59, 59, 59, 59, 65, 69
Sockets:
--------------------------------------------------------------------
JVM socket write (128MiB), 20 iterations
Avg: 87.7ms Min: 79ms, Max: 112ms
Raw: 79, 81, 81, 82, 82, 82, 83, 83, 84, 84, 84, 86, 87, 90, 90, 91, 92, 96, 105, 112
--------------------------------------------------------------------
Ktor socket write (128MiB), 20 iterations
Avg: 675.3ms Min: 572ms, Max: 968ms
Raw: 572, 582, 583, 589, 598, 612, 633, 636, 651, 676, 682, 683, 686, 688, 689, 702, 727, 763, 786, 968
You can reproduce the performance measurements with the following tests:
https://gist.github.com/Malinskiy/2dbe05a38321417fd4f23e1872593806
https://gist.github.com/Malinskiy/0172b369040cabc074ccfea9a787a79c
This is the result of an investigation of the issue raised here https://github.com/Malinskiy/marathon/issues/462
Cheers,
Anton
ContentType.parse("text/html qqq") must fail with error
STR:
- invoke
ContentType.parse("text/html xxx")
ER: fail
AR:ContentType
with value"text/html xxx"
Docs
Improvements for Docker sample in documentation
Feedback from https://kotlinlang.slack.com/archives/C0A974TJ9/p1634659805496800 about sample from documentation article.
./gradlew installDist
has to be run manually before running docker which seems rather odd considering most use cases are deployment on the cloud.- Naming the project docker could be confused with running docker itself
Suggested improved Dockerfile:
FROM gradle:6-jdk8 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle installDist --no-daemon
FROM openjdk:8-jdk
EXPOSE 8080:8080
RUN mkdir /app
COPY --from=build /home/gradle/src/build/install/docker/ /app/
WORKDIR /app/bin
CMD ["./docker"]
Article about storing sensitive data and accessing it in application.conf
We need to describe a secure way of storing sensitive data, like credentials, and a way of accessing them in Ktor application.
Error in 2.0 doc/sample for HttpClient retry
https://helpserver.labs.jb.gg/help/ktor/2.0.0/client-retry.html#configure_retry
status() should be property not function. With latest 2.0 it does not compile.
In multi-module application, a plugin installed in a single module will be executed for requests handled by any module.
Per Ktor docs https://ktor.io/docs/modules.html, installed plugins should only apply to the module in which they are installed. However we are seeing that if a plugin is installed in one module, but not another, the plugin is executed for requests handled by the module that DOES NOT have the plugin installed.This is either a bug, or the documentation is misleading or incomplete on how to separate plugins for different modules.
Example (source, and runnable JAR provided):
I have a Ktor application with 2 modules, each defining a distinct Route,
module1() /module1
module2() /module2
I have the CallLogging plugin installed in module1, but not in module2
However when making calls to routes in either module the CallLogging plugin is executed:
Calling http://localhost:8080/module1
we see in console, from CallLogging plugin
2021-10-07 10:36:30.671 [eventLoopGroupProxy-4-1] TRACE Application - 200 OK: GET - /module1
Calling http://localhost:8080/module2
we see in console, from CallLogging plugin
2021-10-07 10:37:57.069 [eventLoopGroupProxy-4-1] TRACE Application - 200 OK: GET - /module2
Explain method(HttpMethod.Options) in docs for CORS
method(HttpMethod.Options
Is always required in CORS feature because a browser always sends Options preflight request to check CORS (https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request)
But for some reason it is not documented
Please, also stay in sync about API that may be changed here (https://youtrack.jetbrains.com/issue/KTOR-2912)
Update JSON topics using code snippets from the 'codeSnippets' project
Update the 'Modules' topic
https://ktor.io/docs/modules.html
- add information on how to use modules depending on the way used to run a server (https://ktor.io/docs/engines.html#configure)
Generator
start.ktor.io - oauth not importing io.ktor.sessions.* in Security.kt by default causing build error
Summary
Attempting to create a starter project using start.ktor.io has a build error by default if you select Authentication OAuth.
Steps to Reproduce
- Navigate to start.ktor.io
- Maintain default settings
- Gradle Kotlin, Ktor 1.6.3, Netty
- Add Authentication OAuth Plugin
- Generate Project
- Attempt to build project
Detailed Description
The generated project includes a Security.kt in plugins to configure OAuth for Google. Within routing
for auth-oauth-google, there is a line of code:
call.sessions.set(UserSession(principal?.accessToken.toString()))
Attempting to then build the project, we get the following error:
> Task :compileKotlin FAILED
e: ...\ktor-sample\src\main\kotlin\com\example\plugins\Security.kt: (42, 30): Unresolved reference: sessions
e: ...\ktor-sample\src\main\kotlin\com\example\plugins\Security.kt: (42, 43): Unresolved reference: sessions
This is due to the following import missing in Security.kt: import io.ktor.sessions.*
Solution
When generating a project with OAuth, include import io.ktor.sessions.*
in Security.kt
Could not find artifact org.jetbrains.kotlinx:kotlinx-html-jvm:pom:0.7.2
To reproduce create a project with all features selected and the the following properties:
- Build system: Maven
- Ktor version 1.4.0
- Engine: Tomcat
- Configuration: HOCON file
After project generation, sync fails with the following error:
Could not find artifact org.jetbrains.kotlinx:kotlinx-html-jvm:pom:0.7.2 in kotlinx-html (https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven)
Also, build fails with an unresolved reference error:
/home/stexe/projects/ktor_plugin/ktor-sample7/src/main/kotlin/com/example/plugins/Sockets.kt:11:24
Kotlin: Unresolved reference: tls
Infrastructure
Build and test on Apple Silicon Arm
Currently it is not possible to build and test Ktor (server and clients) on Apple Silicon with Xcode 13 and macOS 12. This release removes all x64
frameworks, so every hardcoded macosX64
target has to be replaced. This also applies to curl.
IntelliJ IDEA Plugin
Ktor 2.0.0-eap-256 some dependecies are not imported
When creating a new Ktor project and targeting Ktor 2.0.0-eap-256, some dependencies are not imported by default in gradle file (despite being marked as needed in Plugins list).
These 3 are the ones that I had to import manually:
ktor-server-http-redirect
ktor-server-default-headers
ktor-server-content-negotiation
Env:
IDEA 2021.2.2 (Ultimate Edition)
Build #IU-212.5284.40, built on September 14, 2021
Runtime version: 11.0.12+7-b1504.28 x86_64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 10.15.7
GC: G1 Young Generation, G1 Old Generation
Memory: 2048M
Cores: 16
Kotlin: 212-1.5.10-release-IJ5284.40