diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4f083d7bce..a80533109e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -117,6 +117,9 @@ 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 = "12.1.0.alpha1" } +jettyCompressionServer = { module = "org.eclipse.jetty.compression:jetty-compression-server", version = "12.1.0.alpha1" } +jettyCompressionGzip = { module = "org.eclipse.jetty.compression:jetty-compression-gzip", version = "12.1.0.alpha1" } +jettyCompressionZstandard = { module = "org.eclipse.jetty.compression:jetty-compression-zstandard", 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" } diff --git a/misk/build.gradle.kts b/misk/build.gradle.kts index adc8bc64e5..d2fe4804cb 100644 --- a/misk/build.gradle.kts +++ b/misk/build.gradle.kts @@ -15,6 +15,9 @@ dependencies { api(libs.jacksonAnnotations) api(libs.jacksonDatabind) api(libs.jakartaInject) + api(libs.jettyCompressionServer) + api(libs.jettyCompressionGzip) + api(libs.jettyCompressionZstandard) api(libs.jettyServer) api(libs.jettyServletApi) api(libs.jettyUtil) diff --git a/misk/src/main/kotlin/misk/web/MiskWebModule.kt b/misk/src/main/kotlin/misk/web/MiskWebModule.kt index 6e9f0ec589..3bc6fbccfa 100644 --- a/misk/src/main/kotlin/misk/web/MiskWebModule.kt +++ b/misk/src/main/kotlin/misk/web/MiskWebModule.kt @@ -92,9 +92,9 @@ import misk.web.mdc.RequestURILogContextProvider import misk.web.proxy.WebProxyEntry import misk.web.resources.StaticResourceEntry import misk.web.shutdown.GracefulShutdownModule +import org.eclipse.jetty.compression.server.CompressionHandler import org.eclipse.jetty.io.EofException import org.eclipse.jetty.server.handler.StatisticsHandler -import org.eclipse.jetty.server.handler.gzip.GzipHandler import org.eclipse.jetty.util.VirtualThreads import org.eclipse.jetty.util.thread.ExecutorThreadPool import org.eclipse.jetty.util.thread.QueuedThreadPool @@ -327,8 +327,8 @@ class MiskWebModule @JvmOverloads constructor( @Provides @Singleton - fun provideGzipHandler(): GzipHandler { - return GzipHandler() + fun provideCompressionHandler(): CompressionHandler { + return CompressionHandler() } @Provides diff --git a/misk/src/main/kotlin/misk/web/jetty/JettyService.kt b/misk/src/main/kotlin/misk/web/jetty/JettyService.kt index 45865b1162..196f6b977c 100644 --- a/misk/src/main/kotlin/misk/web/jetty/JettyService.kt +++ b/misk/src/main/kotlin/misk/web/jetty/JettyService.kt @@ -16,6 +16,10 @@ 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.compression.gzip.GzipCompression +import org.eclipse.jetty.compression.server.CompressionConfig +import org.eclipse.jetty.compression.server.CompressionHandler +import org.eclipse.jetty.compression.zstandard.ZstandardCompression import org.eclipse.jetty.ee8.servlet.FilterHolder import org.eclipse.jetty.ee8.servlet.ServletContextHandler import org.eclipse.jetty.ee8.servlet.ServletHolder @@ -36,7 +40,6 @@ import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.ServerConnector import org.eclipse.jetty.server.SslConnectionFactory import org.eclipse.jetty.server.handler.StatisticsHandler -import org.eclipse.jetty.server.handler.gzip.GzipHandler import org.eclipse.jetty.unixdomain.server.UnixDomainServerConnector import org.eclipse.jetty.util.ssl.SslContextFactory import org.eclipse.jetty.util.thread.ThreadPool @@ -62,7 +65,7 @@ class JettyService @Inject internal constructor( threadPool: ThreadPool, private val connectionMetricsCollector: JettyConnectionMetricsCollector, private val statisticsHandler: StatisticsHandler, - private val gzipHandler: GzipHandler, + private val compressionHandler: CompressionHandler, ) : AbstractIdleService() { private val server = Server(threadPool) val healthServerUrl: HttpUrl? get() = server.healthUrl @@ -293,16 +296,33 @@ class JettyService @Inject internal constructor( val serverStats = ConnectionStatistics() server.addBean(serverStats) - gzipHandler.server = server + compressionHandler.server = server if (webConfig.gzip) { - gzipHandler.minGzipSize = webConfig.minGzipSize - gzipHandler.addIncludedMethods("POST") - gzipHandler.addExcludedMimeTypes(MediaTypes.APPLICATION_GRPC) + compressionHandler.putCompression(ZstandardCompression().apply { + this.minCompressSize = webConfig.minGzipSize + }) + compressionHandler.putCompression(GzipCompression().apply { + this.minCompressSize = webConfig.minGzipSize + }) + compressionHandler.putConfiguration("/", CompressionConfig.builder() + .defaults() + .compressExcludeMimeType(MediaTypes.APPLICATION_GRPC) + .decompressExcludeMimeType(MediaTypes.APPLICATION_GRPC) + .compressPreferredEncodings(listOf("zstd")) + .build() + ) } else { - // GET is enabled by default for gzipHandler. - gzipHandler.addExcludedMethods("GET", "POST") + compressionHandler.putConfiguration("/", CompressionConfig.builder() + .compressExcludeMethod("GET") + .compressExcludeMethod("POST") + .decompressExcludeMethod("GET") + .decompressExcludeMethod("POST") + .compressExcludeMimeType(MediaTypes.APPLICATION_GRPC) + .decompressExcludeMimeType(MediaTypes.APPLICATION_GRPC) + .build() + ) } - servletContextHandler.insertHandler(gzipHandler) + servletContextHandler.insertHandler(compressionHandler) server.handler = statisticsHandler