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: Upgrade to Jetty 12.1 alpha with EE8 #3383

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ subprojects {
add("api", platform(rootProject.libs.jacksonBom))
add("api", platform(rootProject.libs.jerseyBom))
add("api", platform(rootProject.libs.jettyBom))
add("api", platform(rootProject.libs.jettyEe8Bom))
add("api", platform(rootProject.libs.kotlinBom))
add("api", platform(rootProject.libs.nettyBom))
add("api", platform(rootProject.libs.prometheusClientBom))
Expand Down
16 changes: 9 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,21 @@ jerseyBom = { module = "org.glassfish.jersey:jersey-bom", version = "3.1.10" }
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version = "26.0.2" }
jettyAlpnServer = { module = "org.eclipse.jetty:jetty-alpn-server" }
jettyAlpnServerJava = { module = "org.eclipse.jetty:jetty-alpn-java-server" }
jettyBom = { module = "org.eclipse.jetty:jetty-bom", version = "10.0.20" }
jettyBom = { module = "org.eclipse.jetty:jetty-bom", version = "12.1.0.alpha1" }
jettyEe8Bom = { module = "org.eclipse.jetty.ee8:jetty-ee8-bom", version = "12.1.0.alpha1" }
jettyEe8WebsocketServer = { module = "org.eclipse.jetty.ee8.websocket:jetty-ee8-websocket-jetty-server" }
jettyHttp = { module = "org.eclipse.jetty:jetty-http" }
jettyHttp2 = { module = "org.eclipse.jetty.http2:http2-server" }
jettyHttp2 = { module = "org.eclipse.jetty.http2:jetty-http2-server" }
jettyIo = { module = "org.eclipse.jetty:jetty-io" }
jettyServer = { module = "org.eclipse.jetty:jetty-server" }
jettyServlet = { module = "org.eclipse.jetty:jetty-servlet" }
jettyServlet = { module = "org.eclipse.jetty.ee8:jetty-ee8-servlet" }
jettyServletApi = { module = "org.eclipse.jetty.toolchain:jetty-servlet-api", version = "4.0.6" }
jettyServlets = { module = "org.eclipse.jetty:jetty-servlets" }
jettyServlets = { module = "org.eclipse.jetty.ee8:jetty-ee8-servlets" }
jettyUds = { module = "org.eclipse.jetty:jetty-unixdomain-server" }
jettyUnixSocket = { module = "org.eclipse.jetty:jetty-unixsocket-server" }
jettyUnixSocket = { module = "org.eclipse.jetty:jetty-unixdomain-server" }
jettyUtil = { module = "org.eclipse.jetty:jetty-util" }
jettyWebsocketApi = { module = "org.eclipse.jetty.websocket:websocket-jetty-api" }
jettyWebsocketServer = { module = "org.eclipse.jetty.websocket:websocket-jetty-server" }
jettyWebsocketApi = { module = "org.eclipse.jetty.websocket:jetty-websocket-jetty-api" }
jettyWebsocketServer = { module = "org.eclipse.jetty.websocket:jetty-websocket-jetty-server" }
jnrUnixsocket = { module = "com.github.jnr:jnr-unixsocket", version = "0.38.23" }
jooq = { module = "org.jooq:jooq", version = "3.18.25" }
jsqlparser = { module = "com.github.jsqlparser:jsqlparser", version = "5.1" }
Expand Down
1 change: 1 addition & 0 deletions misk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies {
api(project(":misk-service"))
implementation(libs.jCommander)
implementation(libs.jettyAlpnServer)
implementation(libs.jettyEe8WebsocketServer)
implementation(libs.jettyHttp)
implementation(libs.jettyHttp2)
implementation(libs.jettyIo)
Expand Down
8 changes: 4 additions & 4 deletions misk/src/main/kotlin/misk/web/jetty/JettyHealthService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import misk.annotation.ExperimentalMiskApi
import misk.web.WebConfig
import mu.KLogger
import okhttp3.HttpUrl
import org.eclipse.jetty.ee8.servlet.ServletContextHandler
import org.eclipse.jetty.ee8.servlet.ServletHolder
import org.eclipse.jetty.ee8.websocket.server.config.JettyWebSocketServletContainerInitializer
import org.eclipse.jetty.http.UriCompliance
import org.eclipse.jetty.io.ConnectionStatistics
import org.eclipse.jetty.server.HttpConfiguration
Expand All @@ -16,10 +19,7 @@ import org.eclipse.jetty.server.NetworkConnector
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.server.handler.StatisticsHandler
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder
import org.eclipse.jetty.util.thread.ExecutorThreadPool
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer
import wisp.logging.getLogger
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadPoolExecutor
Expand Down Expand Up @@ -144,7 +144,7 @@ internal class JettyHealthService @Inject internal constructor(

JettyWebSocketServletContainerInitializer.configure(servletContextHandler, null)
server.addManaged(servletContextHandler)
statisticsHandler.handler = servletContextHandler
statisticsHandler.handler = servletContextHandler.get()
}

private fun setupServer() {
Expand Down
94 changes: 31 additions & 63 deletions misk/src/main/kotlin/misk/web/jetty/JettyService.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package misk.web.jetty

import com.google.common.base.Stopwatch
import com.google.common.base.Strings
import com.google.common.util.concurrent.AbstractIdleService
import com.google.common.util.concurrent.ThreadFactoryBuilder
import com.squareup.wire.internal.newMutableList
Expand All @@ -17,6 +16,11 @@ import misk.web.jetty.JettyHealthService.Companion.jettyHealthServiceEnabled
import misk.web.mediatype.MediaTypes
import okhttp3.HttpUrl
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory
import org.eclipse.jetty.ee8.servlet.FilterHolder
import org.eclipse.jetty.ee8.servlet.ServletContextHandler
import org.eclipse.jetty.ee8.servlet.ServletHolder
import org.eclipse.jetty.ee8.servlets.CrossOriginFilter
import org.eclipse.jetty.ee8.websocket.server.config.JettyWebSocketServletContainerInitializer
import org.eclipse.jetty.http.UriCompliance
import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory
Expand All @@ -31,19 +35,11 @@ import org.eclipse.jetty.server.SecureRequestCustomizer
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.server.SslConnectionFactory
import org.eclipse.jetty.server.handler.ContextHandler
import org.eclipse.jetty.server.handler.StatisticsHandler
import org.eclipse.jetty.server.handler.gzip.GzipHandler
import org.eclipse.jetty.servlet.FilterHolder
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletHolder
import org.eclipse.jetty.servlets.CrossOriginFilter
import org.eclipse.jetty.unixdomain.server.UnixDomainServerConnector
import org.eclipse.jetty.unixsocket.server.UnixSocketConnector
import org.eclipse.jetty.util.JavaVersion
import org.eclipse.jetty.util.ssl.SslContextFactory
import org.eclipse.jetty.util.thread.ThreadPool
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer
import wisp.logging.getLogger
import java.io.File
import java.io.IOException
Expand All @@ -56,7 +52,6 @@ import java.util.EnumSet
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import javax.servlet.DispatcherType

@Singleton
Expand Down Expand Up @@ -258,44 +253,29 @@ class JettyService @Inject internal constructor(
udsConnFactories.add(HTTP2CServerConnectionFactory(httpConfig))
}

if (isJEP380Supported(socketConfig.path)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JEP 380 is the only mechanism on Jetty 12.1

logger.info("Using UnixDomainServerConnector for ${socketConfig.path}")
val udsConnector = UnixDomainServerConnector(
server,
null /* executor */,
null /* scheduler */,
null /* buffer pool */,
webConfig.acceptors ?: -1,
webConfig.selectors ?: -1,
*udsConnFactories.toTypedArray()
)
val socketFile = File(socketConfig.path)
udsConnector.unixDomainPath = socketFile.toPath()
udsConnector.addBean(connectionMetricsCollector.newConnectionListener("http", 0))
udsConnector.name = "uds"

// set file permissions after socket creation so sidecars (e.g. envoy, istio) have access
try {
udsConnector.start()
setFilePermissions(socketFile)
} catch (e: Exception) {
cleanAndThrow(udsConnector, e)
}
server.addConnector(udsConnector)
} else {
val udsConnector = UnixSocketConnector(
server,
null /* executor */,
null /* scheduler */,
null /* buffer pool */,
webConfig.selectors ?: -1,
*udsConnFactories.toTypedArray()
)
udsConnector.setUnixSocket(socketConfig.path)
udsConnector.addBean(connectionMetricsCollector.newConnectionListener("http", 0))
udsConnector.name = "uds"
server.addConnector(udsConnector)
logger.info("Using UnixDomainServerConnector for ${socketConfig.path}")
val udsConnector = UnixDomainServerConnector(
server,
null /* executor */,
null /* scheduler */,
null /* buffer pool */,
webConfig.acceptors ?: -1,
webConfig.selectors ?: -1,
*udsConnFactories.toTypedArray()
)
val socketFile = File(socketConfig.path)
udsConnector.unixDomainPath = socketFile.toPath()
udsConnector.addBean(connectionMetricsCollector.newConnectionListener("http", 0))
udsConnector.name = "uds"

// set file permissions after socket creation so sidecars (e.g. envoy, istio) have access
try {
udsConnector.start()
setFilePermissions(socketFile)
} catch (e: Exception) {
cleanAndThrow(udsConnector, e)
}
server.addConnector(udsConnector)
}

// TODO(mmihic): Force security handler?
Expand All @@ -305,7 +285,7 @@ class JettyService @Inject internal constructor(
JettyWebSocketServletContainerInitializer.configure(servletContextHandler, null)
server.addManaged(servletContextHandler)

statisticsHandler.handler = servletContextHandler
statisticsHandler.handler = servletContextHandler.get()
statisticsHandler.server = server

// Kubernetes sends a SIG_TERM and gives us 30 seconds to stop gracefully.
Expand Down Expand Up @@ -446,11 +426,11 @@ private val Server.httpsUrl: HttpUrl?
}

internal fun NetworkConnector.toHttpUrl(): HttpUrl {
val context = server.getChildHandlerByClass(ContextHandler::class.java)
val context = server.context
val protocol = defaultConnectionFactory.protocol
val scheme = if (protocol.startsWith("SSL-") || protocol == "SSL") "https" else "http"

val virtualHosts = context?.virtualHosts ?: arrayOf<String>()
val virtualHosts = context?.virtualHosts ?: listOf<String>()
val explicitHost = if (virtualHosts.isEmpty()) host else virtualHosts[0]

return HttpUrl.Builder()
Expand All @@ -465,6 +445,7 @@ internal fun NetworkConnector.toHttpUrl(): HttpUrl {
* the response stream before the request stream is completed. It also wants to send HTTP trailers.
*/
private fun HttpConfiguration.customizeForGrpc() {
@Suppress("DEPRECATION")
isDelayDispatchUntilContent = false
}

Expand All @@ -480,19 +461,6 @@ private fun AbstractHTTP2ServerConnectionFactory.customize(webConfig: WebConfig)
}
}

/**
* JEP-380 is supported when running Java 16+ and the provided socket path is non-abstract. Abstract
* socket paths are identified by paths prefixed with an `@` symbol or a null byte.
*/
internal fun isJEP380Supported(
path: String,
javaVersion: Int = JavaVersion.VERSION.major
): Boolean {
return javaVersion >= 16 &&
!Strings.isNullOrEmpty(path) &&
!Pattern.compile("^@|\u0000").matcher(path).find()
}

private fun setFilePermissions(file: File) {
try {
Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("rw-rw-rw-"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import misk.web.ServletHttpCall
import misk.web.actions.WebSocketListener
import okhttp3.Headers
import okhttp3.Headers.Companion.headersOf
import org.eclipse.jetty.ee8.nested.Response
import org.eclipse.jetty.http.HttpFields
import org.eclipse.jetty.server.Response
import java.util.function.Supplier

internal class JettyServletUpstreamResponse(
Expand Down
12 changes: 6 additions & 6 deletions misk/src/main/kotlin/misk/web/jetty/JettyWebSocket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import okhttp3.Headers
import okio.ByteString
import okio.ByteString.Companion.toByteString
import okio.utf8Size
import org.eclipse.jetty.websocket.api.Session
import org.eclipse.jetty.websocket.api.WebSocketAdapter
import org.eclipse.jetty.websocket.api.WriteCallback
import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest
import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse
import org.eclipse.jetty.websocket.server.JettyWebSocketCreator
import org.eclipse.jetty.ee8.websocket.api.Session
import org.eclipse.jetty.ee8.websocket.api.WebSocketAdapter
import org.eclipse.jetty.ee8.websocket.api.WriteCallback
import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeRequest
import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeResponse
import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketCreator
import java.util.ArrayDeque

private const val MAX_QUEUE_SIZE = 16 * 1024 * 1024
Expand Down
18 changes: 7 additions & 11 deletions misk/src/main/kotlin/misk/web/jetty/WebActionsServlet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ import okio.BufferedSink
import okio.buffer
import okio.sink
import okio.source
import org.eclipse.jetty.ee8.nested.Request
import org.eclipse.jetty.ee8.nested.Response
import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeResponse
import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketServlet
import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketServletFactory
import org.eclipse.jetty.http.HttpMethod
import org.eclipse.jetty.server.Request
import org.eclipse.jetty.server.Response
import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.unixdomain.server.UnixDomainServerConnector
import org.eclipse.jetty.unixsocket.server.UnixSocketConnector
import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory
import wisp.logging.getLogger
import java.net.HttpURLConnection
import java.net.InetSocketAddress
import java.net.ProtocolException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
Expand Down Expand Up @@ -128,12 +128,8 @@ internal class WebActionsServlet @Inject constructor(
(this.connector as UnixDomainServerConnector).unixDomainPath.toString()
)

is UnixSocketConnector -> SocketAddress.Unix(
(this.connector as UnixSocketConnector).unixSocket
)

is ServerConnector -> SocketAddress.Network(
this.endPoint.remoteAddress.address.hostAddress,
(this.remoteAddress as InetSocketAddress).hostString,
(this.connector as ServerConnector).localPort
)

Expand Down
8 changes: 4 additions & 4 deletions misk/src/test/kotlin/misk/web/ssl/Http2ConnectivityTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package misk.web.ssl
import ch.qos.logback.classic.Level
import com.google.inject.Guice
import com.google.inject.Provides
import jakarta.inject.Inject
import jakarta.inject.Singleton
import misk.Action
import misk.MiskDefault
import misk.MiskTestingServiceModule
Expand Down Expand Up @@ -48,8 +50,6 @@ import java.io.IOException
import java.net.SocketTimeoutException
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.TimeUnit
import jakarta.inject.Inject
import jakarta.inject.Singleton
import javax.servlet.http.HttpServletRequest
import kotlin.test.assertFailsWith

Expand Down Expand Up @@ -264,7 +264,7 @@ class Http2ConnectivityTest {
@ResponseContentType(MediaTypes.TEXT_PLAIN_UTF8)
fun disconnect(): Response<String> {
val request = actionScopedServletRequest.get() as org.eclipse.jetty.server.Request
request.httpChannel.abort(Exception("boom")) // Synthesize a connectivity failure.
request.fail(Exception("boom")) // Synthesize a connectivity failure.

return Response(body = "")
}
Expand All @@ -278,7 +278,7 @@ class Http2ConnectivityTest {
@ResponseContentType(MediaTypes.TEXT_PLAIN_UTF8)
fun disconnect(): ResponseBody {
val request = actionScopedServletRequest.get() as org.eclipse.jetty.server.Request
request.httpChannel.abort(Exception("boom")) // Synthesize a connectivity failure.
request.fail(Exception("boom")) // Synthesize a connectivity failure.

return object : ResponseBody {
override fun writeTo(sink: BufferedSink) {
Expand Down
Loading