Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] KTOR-6734 Jetty engine: Upgrade Jetty dependencies to the latest version 12 #4575

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
12 changes: 6 additions & 6 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ netty = "4.1.116.Final"
netty-tcnative = "2.0.69.Final"

jetty = "9.4.56.v20240826"
jetty-jakarta = "11.0.24"
jetty-jakarta = "12.0.16"
jetty-alpn-api = "1.1.3.v20160715"
jetty-alpn-boot = "8.1.13.v20181017"
jetty-alpn-openjdk8 = "9.4.56.v20240826"
Expand Down Expand Up @@ -160,12 +160,12 @@ jetty-alpn-openjdk8-server = { module = "org.eclipse.jetty:jetty-alpn-openjdk8-s
jetty-alpn-openjdk8-client = { module = "org.eclipse.jetty:jetty-alpn-openjdk8-client", version.ref = "jetty-alpn-openjdk8" }

jetty-client-jakarta = { module = "org.eclipse.jetty:jetty-client", version.ref = "jetty-jakarta" }
jetty-http2-server-jakarta = { module = "org.eclipse.jetty.http2:http2-server", version.ref = "jetty-jakarta" }
jetty-http2-client-jakarta = { module = "org.eclipse.jetty.http2:http2-client", version.ref = "jetty-jakarta" }
jetty-http2-client-transport-jakarta = { module = "org.eclipse.jetty.http2:http2-http-client-transport", version.ref = "jetty-jakarta" }
jetty-http3-server-jakarta = { module = "org.eclipse.jetty.http3:jetty-http3-server", version.ref = "jetty-jakarta" }
jetty-http3-client-jakarta = { module = "org.eclipse.jetty.http3:jetty-http3-client", version.ref = "jetty-jakarta" }
jetty-http3-client-transport-jakarta = { module = "org.eclipse.jetty.http3:jetty-http3-client-transport", version.ref = "jetty-jakarta" }
jetty-server-jakarta = { module = "org.eclipse.jetty:jetty-server", version.ref = "jetty-jakarta" }
jetty-servlets-jakarta = { module = "org.eclipse.jetty:jetty-servlets", version.ref = "jetty-jakarta" }
jetty-servlet-jakarta = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "jetty-jakarta" }
jetty-servlets-jakarta = { module = "org.eclipse.jetty.ee10:jetty-ee10-servlets", version.ref = "jetty-jakarta" }
jetty-servlet-jakarta = { module = "org.eclipse.jetty.ee10:jetty-ee10-servlet", version.ref = "jetty-jakarta" }
jetty-alpn-server-jakarta = { module = "org.eclipse.jetty:jetty-alpn-server", version.ref = "jetty-jakarta" }
jetty-alpn-java-server-jakarta = { module = "org.eclipse.jetty:jetty-alpn-java-server", version.ref = "jetty-jakarta" }
jetty-alpn-java-client-jakarta = { module = "org.eclipse.jetty:jetty-alpn-java-client", version.ref = "jetty-jakarta" }
Expand Down
2 changes: 1 addition & 1 deletion ktor-client/ktor-client-jetty-jakarta/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ kotlin.sourceSets {
dependencies {
api(project(":ktor-client:ktor-client-core"))

api(libs.jetty.http2.client.jakarta)
api(libs.jetty.http3.client.jakarta)
api(libs.jetty.alpn.openjdk8.client)
api(libs.jetty.alpn.java.client)
}
Expand Down
2 changes: 1 addition & 1 deletion ktor-server/ktor-server-jetty-jakarta/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ kotlin {
api(libs.jetty.alpn.server.jakarta)
api(libs.jetty.alpn.java.server.jakarta)
api(libs.jetty.alpn.openjdk8.server)
api(libs.jetty.http2.server.jakarta)
api(libs.jetty.http3.server.jakarta)
}
}
jvmTest {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,27 @@
/*
* Copyright 2014-2023 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.server.jetty.jakarta

import io.ktor.server.application.*
import io.ktor.server.jetty.jakarta.internal.*
import io.ktor.server.servlet.jakarta.*
import io.ktor.server.engine.*
import io.ktor.utils.io.*
import jakarta.servlet.http.*
import org.eclipse.jetty.server.*
import kotlin.coroutines.*
import org.eclipse.jetty.server.Request
import org.eclipse.jetty.server.Response
import kotlin.coroutines.CoroutineContext


@InternalAPI
public class JettyApplicationCall(
application: Application,
request: Request,
servletRequest: HttpServletRequest,
servletResponse: HttpServletResponse,
engineContext: CoroutineContext,
userContext: CoroutineContext,
coroutineContext: CoroutineContext
) : AsyncServletApplicationCall(
application,
servletRequest,
servletResponse,
engineContext,
userContext,
JettyUpgradeImpl,
coroutineContext
) {
response: Response,
override val coroutineContext: CoroutineContext
) : BaseApplicationCall(application) {

override val response: JettyApplicationResponse = JettyApplicationResponse(
this,
servletRequest,
servletResponse,
engineContext,
userContext,
request,
coroutineContext
)
override val request: JettyApplicationRequest = JettyApplicationRequest(this, request)
override val response: JettyApplicationResponse = JettyApplicationResponse(this, request, response, coroutineContext)

init {
putResponseAttribute()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2023 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.server.jetty.jakarta
Expand All @@ -16,14 +16,12 @@ public class JettyApplicationEngine(
environment: ApplicationEnvironment,
monitor: Events,
developmentMode: Boolean,
configure: Configuration,
configuration: Configuration,
private val applicationProvider: () -> Application
) : JettyApplicationEngineBase(environment, monitor, developmentMode, configure, applicationProvider) {

private val dispatcher = server.threadPool.asCoroutineDispatcher()
) : JettyApplicationEngineBase(environment, monitor, developmentMode, configuration, applicationProvider) {

override fun start(wait: Boolean): JettyApplicationEngine {
server.handler = JettyKtorHandler(environment, this::pipeline, dispatcher, configuration, applicationProvider)
server.handler = JettyKtorHandler(environment, pipeline, applicationProvider)
super.start(wait)
return this
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2023 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.server.jetty.jakarta
Expand All @@ -10,8 +10,6 @@ import io.ktor.server.engine.*
import kotlinx.coroutines.CompletableJob
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/**
* [ApplicationEngine] base type for running in a standalone Jetty
Expand All @@ -23,7 +21,7 @@ public open class JettyApplicationEngineBase(
/**
* Application engine configuration specifying engine-specific options such as parallelism level.
*/
public val configuration: Configuration,
private val configuration: Configuration,
private val applicationProvider: () -> Application
) : BaseApplicationEngine(environment, monitor, developmentMode) {

Expand All @@ -40,10 +38,10 @@ public open class JettyApplicationEngineBase(
/**
* The duration of time that a connection can be idle before the connector takes action to close the connection.
*/
public var idleTimeout: Duration = 30.seconds
public var idleTimeout: Long = -1
}

private var cancellationJob: CompletableJob? = null
private var cancellationDeferred: CompletableJob? = null

/**
* Jetty server instance being configuring and starting
Expand All @@ -55,7 +53,7 @@ public open class JettyApplicationEngineBase(

override fun start(wait: Boolean): JettyApplicationEngineBase {
server.start()
cancellationJob = stopServerOnCancellation(
cancellationDeferred = stopServerOnCancellation(
applicationProvider(),
configuration.shutdownGracePeriod,
configuration.shutdownTimeout
Expand All @@ -75,7 +73,7 @@ public open class JettyApplicationEngineBase(
}

override fun stop(gracePeriodMillis: Long, timeoutMillis: Long) {
cancellationJob?.complete()
cancellationDeferred?.complete()
monitor.raise(ApplicationStopPreparing, environment)
server.stopTimeout = timeoutMillis
server.stop()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.server.jetty.jakarta

import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.request.*
import io.ktor.utils.io.*
import io.ktor.utils.io.jvm.javaio.*
import org.eclipse.jetty.io.*
import org.eclipse.jetty.server.*

@InternalAPI
public class JettyApplicationRequest(
call: PipelineCall,
request: Request
) : BaseApplicationRequest(call) {

override val cookies: RequestCookies = JettyRequestCookies(this, request)

override val engineHeaders: Headers = JettyHeaders(request)

override val engineReceiveChannel: ByteReadChannel = Content.Source.asInputStream(request).toByteReadChannel()

override val local: RequestConnectionPoint = JettyConnectionPoint(request)

override val queryParameters: Parameters by lazy { encodeParameters(rawQueryParameters) }

override val rawQueryParameters: Parameters by lazy(LazyThreadSafetyMode.NONE) {
val uri = request.httpURI.query ?: return@lazy Parameters.Empty
parseQueryString(uri, decode = false)
}
}

@InternalAPI
public class JettyRequestCookies(
request: JettyApplicationRequest,
private val jettyRequest: Request
) : RequestCookies(request) {
override fun fetchCookies(): Map<String, String> {
return Request.getCookies(jettyRequest).associate { it.name to it.value }
}
}

@InternalAPI
public class JettyHeaders(
private val jettyRequest: Request
) : Headers {
override val caseInsensitiveName: Boolean = true

override fun entries(): Set<Map.Entry<String, List<String>>> {
return jettyRequest.headers.fieldNamesCollection.map {
object : Map.Entry<String, List<String>> {
override val key: String = it
override val value: List<String> = jettyRequest.headers.getValuesList(it)
}
}.toSet()
}

override fun getAll(name: String): List<String>? = jettyRequest.headers.getValuesList(name)

override fun get(name: String): String? = jettyRequest.headers.get(name)

override fun isEmpty(): Boolean = jettyRequest.headers.size() == 0

override fun names(): Set<String> = jettyRequest.headers.fieldNamesCollection
}

@InternalAPI
public class JettyConnectionPoint(
request: Request
) : RequestConnectionPoint {
@Deprecated("Use localHost or serverHost instead")
override val host: String = request.httpURI.host

override val localAddress: String = Request.getLocalAddr(request)

override val localHost: String = Request.getServerName(request)

override val localPort: Int = Request.getLocalPort(request)

override val method: HttpMethod = HttpMethod.parse(request.method)

@Deprecated("Use localPort or serverPort instead")
override val port: Int = request.httpURI.port

override val remoteAddress: String = Request.getRemoteAddr(request)

override val remoteHost: String = Request.getServerName(request)

override val remotePort: Int = Request.getRemotePort(request)

override val scheme: String = request.httpURI.scheme

override val serverHost: String = Request.getServerName(request)

override val serverPort: Int = Request.getServerPort(request)

override val uri: String = request.httpURI.pathQuery

override val version: String = request.connectionMetaData.httpVersion.asString()
}
Loading
Loading