From bfb6ff82bf603d1077604e09c93a756bcbd4f9b8 Mon Sep 17 00:00:00 2001 From: Amer Agovic Date: Fri, 1 May 2026 13:47:23 -0500 Subject: [PATCH] Upgrade Jetty and harden WebSocket upgrade lifecycle --- build.gradle | 2 +- .../java/com/reliancy/jabba/Response.java | 21 ++++++++++++------- .../com/reliancy/jabba/servlet/JettyApp.java | 4 +++- .../jabba/servlet/ServletResponse.java | 1 + 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index eb615fa..a03a7dc 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ tasks.withType(JavaCompile) { } dependencies { - def jettyVersion="12.0.15" + def jettyVersion="12.0.32" def bstoreVersion="1.0.0-SNAPSHOT" implementation "org.eclipse.jetty:jetty-server:${jettyVersion}" implementation "org.eclipse.jetty.http2:jetty-http2-server:${jettyVersion}" diff --git a/src/main/java/com/reliancy/jabba/Response.java b/src/main/java/com/reliancy/jabba/Response.java index 751b32a..5393f42 100644 --- a/src/main/java/com/reliancy/jabba/Response.java +++ b/src/main/java/com/reliancy/jabba/Response.java @@ -42,9 +42,10 @@ public abstract class Response { protected String content_type; protected Integer status; protected ResponseState state = ResponseState.CREATED; - protected final ArrayList headers=new ArrayList<>(); - protected final ArrayList cookies=new ArrayList<>(); - protected CompletableFuture promise; + protected final ArrayList headers=new ArrayList<>(); + protected final ArrayList cookies=new ArrayList<>(); + protected CompletableFuture promise; + protected boolean upgradedToWebSocket; protected Response(Request request) { this.request = request; @@ -154,9 +155,13 @@ public abstract class Response { public abstract void complete(); - public boolean isPromised() { - return promise!=null; - } + public boolean isPromised() { + return promise!=null; + } + + public boolean isUpgradedToWebSocket() { + return upgradedToWebSocket; + } /** * Initiate an async promise chain using supplyAsync. @@ -268,5 +273,5 @@ public abstract class Response { * * TODO: Implement in ServletResponse using Jakarta WebSocket API */ - public abstract WebSocketSession upgradeToWebSocket(String route, Session appSession) throws IOException; -} + public abstract WebSocketSession upgradeToWebSocket(String route, Session appSession) throws IOException; +} diff --git a/src/main/java/com/reliancy/jabba/servlet/JettyApp.java b/src/main/java/com/reliancy/jabba/servlet/JettyApp.java index 5dd25d7..c9a5c89 100644 --- a/src/main/java/com/reliancy/jabba/servlet/JettyApp.java +++ b/src/main/java/com/reliancy/jabba/servlet/JettyApp.java @@ -236,7 +236,9 @@ public class JettyApp extends App implements Servlet { // Only end session if not async (async will end session when completing) if(resp.isPromised()==false){ ss.end(); - resp.complete(); + if(!resp.isUpgradedToWebSocket()){ + resp.complete(); + } }else{ resp.promiseLast((result, error) -> { if(result instanceof Exception){ diff --git a/src/main/java/com/reliancy/jabba/servlet/ServletResponse.java b/src/main/java/com/reliancy/jabba/servlet/ServletResponse.java index e3566d5..25f9d0a 100644 --- a/src/main/java/com/reliancy/jabba/servlet/ServletResponse.java +++ b/src/main/java/com/reliancy/jabba/servlet/ServletResponse.java @@ -186,6 +186,7 @@ public class ServletResponse extends Response { */ @Override public com.reliancy.jabba.WebSocketSession upgradeToWebSocket(String route, com.reliancy.jabba.Session appSession) throws IOException { + upgradedToWebSocket=true; return ServletWebSocketSession.create(this,route, appSession); } }