Skip to content

Commit

Permalink
Update Jetty
Browse files Browse the repository at this point in the history
  • Loading branch information
jaguililla committed Aug 13, 2023
1 parent 2d9f206 commit a9df625
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 73 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ nimaVersion=4.0.0-M1

# http_server_servlet
servletVersion=5.0.0
jettyVersion=11.0.15
jettyVersion=12.0.0

# rest_tools
vertxVersion=4.4.4
Expand Down
2 changes: 1 addition & 1 deletion http/http_client_jetty/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ dependencies {

"api"(project(":http:http_client"))
"api"(platform("org.eclipse.jetty:jetty-bom:$jettyVersion"))
"api"("org.eclipse.jetty.http2:http2-http-client-transport") { exclude(group = "org.slf4j") }
"api"("org.eclipse.jetty.http2:jetty-http2-client-transport") { exclude(group = "org.slf4j") }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,30 @@ import com.hexagonkt.http.model.*
import com.hexagonkt.http.model.ws.WsSession
import com.hexagonkt.http.parseContentType
import org.eclipse.jetty.client.HttpResponseException
import org.eclipse.jetty.client.api.ContentResponse
import org.eclipse.jetty.client.api.Request
import org.eclipse.jetty.client.api.Response
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic
import org.eclipse.jetty.client.http.HttpClientConnectionFactory.HTTP11
import org.eclipse.jetty.client.util.BytesRequestContent
import org.eclipse.jetty.client.util.MultiPartRequestContent
import org.eclipse.jetty.client.util.StringRequestContent
import org.eclipse.jetty.client.ContentResponse
import org.eclipse.jetty.client.Request
import org.eclipse.jetty.client.Response
import org.eclipse.jetty.client.transport.HttpClientTransportDynamic
import org.eclipse.jetty.client.transport.HttpClientConnectionFactory.HTTP11
import org.eclipse.jetty.client.BytesRequestContent
import org.eclipse.jetty.client.MultiPartRequestContent
import org.eclipse.jetty.client.StringRequestContent
import org.eclipse.jetty.http.HttpCookie
import org.eclipse.jetty.http.HttpCookieStore
import org.eclipse.jetty.http.HttpFields
import org.eclipse.jetty.http.HttpFields.EMPTY
import org.eclipse.jetty.http.HttpMethod
import org.eclipse.jetty.http.MultiPart.ContentSourcePart
import org.eclipse.jetty.io.ClientConnector
import java.lang.StringBuilder
import java.lang.UnsupportedOperationException
import java.net.CookieStore
import java.net.URI
import java.util.concurrent.ExecutionException
import java.util.concurrent.Executors
import java.util.concurrent.Flow.Publisher
import java.util.concurrent.SubmissionPublisher
import org.eclipse.jetty.http2.client.HTTP2Client as JettyHttp2Client
import org.eclipse.jetty.http2.client.http.ClientConnectionFactoryOverHTTP2.HTTP2
import org.eclipse.jetty.http2.client.transport.ClientConnectionFactoryOverHTTP2.HTTP2
import org.eclipse.jetty.client.HttpClient as JettyHttpClient
import org.eclipse.jetty.util.ssl.SslContextFactory.Client as ClientSslContextFactory

Expand Down Expand Up @@ -138,8 +140,8 @@ open class JettyClientAdapter : HttpClientPort {
val settings = adapterHttpClient.settings

if (settings.useCookies)
adapterHttpClient.cookies = adapterJettyClient.cookieStore.cookies.map {
Cookie(it.name, it.value, it.maxAge, it.secure)
adapterHttpClient.cookies = adapterJettyClient.httpCookieStore.all().map {
Cookie(it.name, it.value, it.maxAge, it.isSecure)
}

return HttpResponse(
Expand Down Expand Up @@ -174,7 +176,7 @@ open class JettyClientAdapter : HttpClientPort {

if (settings.useCookies) {
val uri = (baseUrl ?: request.url()).toURI()
addCookies(uri, adapterJettyClient.cookieStore, request.cookies)
addCookies(uri, adapterJettyClient.httpCookieStore, request.cookies)
}

val jettyRequest = adapterJettyClient
Expand Down Expand Up @@ -208,32 +210,38 @@ open class JettyClientAdapter : HttpClientPort {
request.parts.forEach { p ->
if (p.submittedFileName == null)
// TODO Add content type if present
multiPart.addFieldPart(p.name, StringRequestContent(p.bodyString()), EMPTY)
multiPart.addPart(
ContentSourcePart(p.name, null, EMPTY, StringRequestContent(p.bodyString()))
)
else
multiPart.addFilePart(
p.name,
p.submittedFileName,
BytesRequestContent(bodyToBytes(p.body)),
EMPTY
multiPart.addPart(
ContentSourcePart(
p.name,
p.submittedFileName,
EMPTY,
BytesRequestContent(bodyToBytes(p.body)),
)
)
}

request.formParameters
.forEach { (k, v) ->
v.strings().forEach { multiPart.addFieldPart(k, StringRequestContent(it), EMPTY) }
v.strings().forEach {
multiPart.addPart(ContentSourcePart(k, null, EMPTY, StringRequestContent(it)))
}
}

multiPart.close()

return multiPart
}

private fun addCookies(uri: URI, store: CookieStore, cookies: List<Cookie>) {
private fun addCookies(uri: URI, store: HttpCookieStore, cookies: List<Cookie>) {
cookies.forEach {
val httpCookie = java.net.HttpCookie(it.name, it.value)
httpCookie.secure = it.secure
httpCookie.maxAge = it.maxAge
store.add(uri, httpCookie)
store.add(uri, HttpCookie.from(httpCookie))
}
}

Expand Down
12 changes: 6 additions & 6 deletions http/http_client_jetty_ws/api/http_client_jetty_ws.api
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ public final class com/hexagonkt/http/client/jetty/JettyClientWsSession : com/he
public fun send ([B)V
}

public final class com/hexagonkt/http/client/jetty/JettyWebSocketAdapter : org/eclipse/jetty/websocket/api/WebSocketAdapter {
public final class com/hexagonkt/http/client/jetty/JettyWebSocketAdapter {
public fun <init> (Ljava/net/URI;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)V
public fun onWebSocketBinary ([BII)V
public fun onWebSocketClose (ILjava/lang/String;)V
public fun onWebSocketConnect (Lorg/eclipse/jetty/websocket/api/Session;)V
public fun onWebSocketError (Ljava/lang/Throwable;)V
public fun onWebSocketText (Ljava/lang/String;)V
public final fun onWebSocketBinary (Lorg/eclipse/jetty/websocket/api/Session;Ljava/nio/ByteBuffer;Lorg/eclipse/jetty/websocket/api/Callback;)V
public final fun onWebSocketClose (Lorg/eclipse/jetty/websocket/api/Session;ILjava/lang/String;)V
public final fun onWebSocketConnect (Lorg/eclipse/jetty/websocket/api/Session;)V
public final fun onWebSocketError (Ljava/lang/Throwable;)V
public final fun onWebSocketText (Lorg/eclipse/jetty/websocket/api/Session;Ljava/lang/String;)V
}

public final class com/hexagonkt/http/client/jetty/JettyWsClientAdapter : com/hexagonkt/http/client/jetty/JettyClientAdapter {
Expand Down
2 changes: 1 addition & 1 deletion http/http_client_jetty_ws/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ apply(from = "$rootDir/gradle/detekt.gradle")

dependencies {
"api"(project(":http:http_client_jetty"))
"api"("org.eclipse.jetty.websocket:websocket-jetty-client")
"api"("org.eclipse.jetty.websocket:jetty-websocket-jetty-client")
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.hexagonkt.http.client.jetty

import com.hexagonkt.http.model.HttpRequestPort
import com.hexagonkt.http.model.ws.WsSession
import org.eclipse.jetty.websocket.api.Callback.NOOP
import org.eclipse.jetty.websocket.api.Session
import java.net.URI
import java.nio.ByteBuffer
Expand All @@ -21,22 +22,22 @@ class JettyClientWsSession(
get() = throw UnsupportedOperationException()

override fun send(data: ByteArray) {
session.remote.sendBytes(ByteBuffer.wrap(data))
session.sendBinary(ByteBuffer.wrap(data), NOOP)
}

override fun send(text: String) {
session.remote.sendString(text)
session.sendText(text, NOOP)
}

override fun ping(data: ByteArray) {
session.remote.sendPing(ByteBuffer.wrap(data))
session.sendPing(ByteBuffer.wrap(data), NOOP)
}

override fun pong(data: ByteArray) {
session.remote.sendPong(ByteBuffer.wrap(data))
session.sendPong(ByteBuffer.wrap(data), NOOP)
}

override fun close(status: Int, reason: String) {
session.close(status, reason)
session.close(status, reason, NOOP)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package com.hexagonkt.http.client.jetty

import com.hexagonkt.http.model.ws.WsSession
import org.eclipse.jetty.websocket.api.Callback
import org.eclipse.jetty.websocket.api.Session
import org.eclipse.jetty.websocket.api.WebSocketAdapter
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen
import org.eclipse.jetty.websocket.api.annotations.WebSocket
import java.net.URI
import java.nio.ByteBuffer

@WebSocket
class JettyWebSocketAdapter(
private val uri: URI,
private val onConnect: WsSession.() -> Unit,
Expand All @@ -13,30 +19,31 @@ class JettyWebSocketAdapter(
private val onPing: WsSession.(data: ByteArray) -> Unit,
private val onPong: WsSession.(data: ByteArray) -> Unit,
private val onClose: WsSession.(status: Int, reason: String) -> Unit,
) : WebSocketAdapter() {

) {
private lateinit var session: Session
private val wsSession by lazy { JettyClientWsSession(uri, session) }

override fun onWebSocketText(message: String) {
@OnWebSocketMessage
fun onWebSocketText(session: Session, message: String) {
wsSession.onText(message)
}

// TODO Handle 'onPing' and 'onPong' (messages probably arriving here)
override fun onWebSocketBinary(payload: ByteArray, offset: Int, len: Int) {
wsSession.onBinary(payload)
@OnWebSocketMessage
fun onWebSocketBinary(session: Session, payload: ByteBuffer, callback: Callback) {
wsSession.onBinary(payload.array())
}

override fun onWebSocketClose(statusCode: Int, reason: String) {
@OnWebSocketClose
fun onWebSocketClose(session: Session, statusCode: Int, reason: String) {
wsSession.onClose(statusCode, reason)
super.onWebSocketClose(statusCode, reason)
}

override fun onWebSocketConnect(sess: Session) {
super.onWebSocketConnect(sess)
@OnWebSocketOpen
fun onWebSocketConnect(sess: Session) {
session = sess
wsSession.onConnect()
}

override fun onWebSocketError(cause: Throwable?) {
super.onWebSocketError(cause)
}
fun onWebSocketError(cause: Throwable) {}
}
6 changes: 3 additions & 3 deletions http/http_server_jetty/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ dependencies {

"api"(project(":http:http_server_servlet"))
"api"(platform("org.eclipse.jetty:jetty-bom:$jettyVersion"))
"api"("org.eclipse.jetty:jetty-webapp")
"api"("org.eclipse.jetty.http2:http2-server")
"api"("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.0")
"api"("org.eclipse.jetty.http2:jetty-http2-server")
"api"("org.eclipse.jetty:jetty-alpn-java-server")

"testImplementation"(project(":http:http_client_jetty_ws"))
"testImplementation"("org.eclipse.jetty.websocket:websocket-jetty-server")
"testImplementation"("org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server:12.0.0")
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory
import org.eclipse.jetty.server.*
import org.eclipse.jetty.server.handler.gzip.GzipHandler
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.servlet.ServletContextHandler.NO_SESSIONS
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
import org.eclipse.jetty.ee10.servlet.ServletContextHandler.NO_SESSIONS
import org.eclipse.jetty.util.ssl.SslContextFactory
import org.eclipse.jetty.util.thread.QueuedThreadPool
import java.security.KeyStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import com.hexagonkt.core.urlOf
import jakarta.servlet.*
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
import org.eclipse.jetty.websocket.api.Session
import org.eclipse.jetty.websocket.api.StatusCode
import org.eclipse.jetty.websocket.api.WebSocketAdapter
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer
import java.util.*
import com.hexagonkt.http.client.HttpClient
import com.hexagonkt.http.client.HttpClientSettings
Expand All @@ -19,6 +17,15 @@ import com.hexagonkt.http.server.HttpServer
import com.hexagonkt.http.handlers.AfterHandler
import com.hexagonkt.http.handlers.PathHandler
import com.hexagonkt.http.server.jetty.JettyServletAdapter
import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer
import org.eclipse.jetty.websocket.api.Callback
import org.eclipse.jetty.websocket.api.Callback.NOOP
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen
import org.eclipse.jetty.websocket.api.annotations.WebSocket
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.condition.DisabledInNativeImage
import kotlin.test.Test
import org.junit.jupiter.api.condition.DisabledOnOs
Expand All @@ -36,28 +43,29 @@ internal class JettyWsServerTest {
JettyWebSocketServletContainerInitializer.configure(context) { _, wsContainer ->
wsContainer.maxTextMessageSize = 65535
wsContainer.addMapping("/ws/*") { _, _ ->
object : WebSocketAdapter() {
override fun onWebSocketConnect(sess: Session) {
super.onWebSocketConnect(sess)
@WebSocket
object {
@OnWebSocketOpen
fun onWebSocketConnect(sess: Session) {
println("Socket Connected: $sess")
}

override fun onWebSocketText(message: String) {
super.onWebSocketText(message)
@OnWebSocketMessage
fun onWebSocketText(session: Session, message: String, callback: Callback) {
println("Received TEXT message: $message")
session.remote.sendString(message + "_")
session.sendText(message + "_", NOOP)
if (message.lowercase(Locale.US).contains("bye")) {
session.close(StatusCode.NORMAL, "Thanks")
session.close(StatusCode.NORMAL, "Thanks", NOOP)
}
}

override fun onWebSocketClose(statusCode: Int, reason: String?) {
super.onWebSocketClose(statusCode, reason)
@OnWebSocketClose
fun onWebSocketClose(session: Session, statusCode: Int, reason: String) {
println("Socket Closed: [$statusCode] $reason")
}

override fun onWebSocketError(cause: Throwable) {
super.onWebSocketError(cause)
@OnWebSocketError
fun onWebSocketError(cause: Throwable) {
cause.printStackTrace(System.err)
}
}
Expand All @@ -79,6 +87,7 @@ internal class JettyWsServerTest {
}

@Test
@Disabled // TODO Fix to make it work with Jetty 12
@DisabledInNativeImage
fun `WS call works OK`() {
startServer()
Expand Down
2 changes: 1 addition & 1 deletion http/http_server_servlet/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ dependencies {

"testImplementation"(project(":logging:logging_jul"))
"testImplementation"(project(":http:http_client_jetty"))
"testImplementation"("org.eclipse.jetty:jetty-webapp")
"testImplementation"("org.eclipse.jetty.ee10:jetty-ee10-webapp:12.0.0")
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.hexagonkt.http.client.HttpClientSettings
import com.hexagonkt.http.client.jetty.JettyClientAdapter
import com.hexagonkt.http.model.NOT_FOUND_404
import com.hexagonkt.http.handlers.path
import org.eclipse.jetty.webapp.WebAppContext
import org.eclipse.jetty.ee10.webapp.WebAppContext
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import kotlin.test.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ abstract class ClientTest(
assertNull(cookiesMap["c3"]) // Secure headers only sent through HTTPS
ok(cookies = listOf(
Cookie("c4", "v4", 60),
Cookie("c5", "v5", secure = true),
Cookie("c5", "v5", secure = false),
Cookie("c6", "v6", secure = true),
))
}

Expand All @@ -134,12 +135,14 @@ abstract class ClientTest(
val responseC4 = response.cookiesMap().require("c4")
assertEquals("v4", responseC4.value)
assertTrue(responseC4.maxAge in 59..60)
assertEquals(Cookie("c5", "v5", secure = true), response.cookiesMap()["c5"])
assertEquals(Cookie("c5", "v5", secure = false), response.cookiesMap()["c5"])
assertNull(response.cookiesMap()["c6"])

val clientC4 = client.cookiesMap().require("c4")
assertEquals("v4", clientC4.value)
assertTrue(clientC4.maxAge in 59..60)
assertEquals(Cookie("c5", "v5", secure = true), client.cookiesMap()["c5"])
assertEquals(Cookie("c5", "v5", secure = false), client.cookiesMap()["c5"])
assertNull(client.cookiesMap()["c6"])
}

@Test fun `Create HTTP clients`() {
Expand Down

0 comments on commit a9df625

Please sign in to comment.