Skip to content

Commit d03391f

Browse files
committed
PrintSocketClient: Attempt to gracefully handle StaticException and closed sessions when calling send()
1 parent 769fcc1 commit d03391f

File tree

2 files changed

+67
-6
lines changed

2 files changed

+67
-6
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package qz.ws;
2+
3+
import org.eclipse.jetty.util.StaticException;
4+
5+
import java.io.IOException;
6+
import java.nio.channels.ClosedChannelException;
7+
import java.util.Locale;
8+
9+
/**
10+
* <code>ClosedChannelException</code> wrapper class for handling edge-cases where Jetty nests or hides
11+
* the underlying <code>Exception</code> cause. Inspired by #1300 and #1414
12+
*/
13+
public class ClosedSocketException extends ClosedChannelException {
14+
public ClosedSocketException(String message) {
15+
super();
16+
this.initCause(new IOException(message));
17+
}
18+
19+
public ClosedSocketException(Throwable t) {
20+
super();
21+
this.initCause(t);
22+
}
23+
24+
public static void filter(Throwable t) throws ClosedChannelException {
25+
Throwable throwable = t;
26+
while(true) {
27+
if(throwable instanceof ClosedChannelException) {
28+
throw (ClosedChannelException)throwable;
29+
}
30+
if(throwable != null) {
31+
throwable = throwable.getCause();
32+
} else {
33+
break;
34+
}
35+
}
36+
37+
if (messageMatchesClosed(t)) {
38+
throw new ClosedSocketException(t);
39+
}
40+
}
41+
42+
/**
43+
* Check if a <code>Throwable</code> or its cause matches a <code>StaticException</code>
44+
* with "closed" in the message string.
45+
*/
46+
private static boolean messageMatchesClosed(Throwable t) {
47+
Throwable throwable = t;
48+
while(true) {
49+
if(throwable == null) {
50+
return false;
51+
} else if(!(throwable instanceof StaticException)) {
52+
// go deeper
53+
throwable = throwable.getCause();
54+
} else {
55+
break;
56+
}
57+
}
58+
StaticException staticException = (StaticException)throwable;
59+
return staticException.getMessage() != null && staticException.getMessage().toLowerCase(Locale.ENGLISH).contains("closed");
60+
}
61+
}

src/qz/ws/PrintSocketClient.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -828,14 +828,14 @@ public static void sendStream(Session session, StreamEvent event, Runnable close
828828
*/
829829
private static synchronized void send(Session session, JSONObject reply) throws WebSocketException, ClosedChannelException {
830830
try {
831-
session.getRemote().sendString(reply.toString());
831+
if(session.isOpen()) {
832+
session.getRemote().sendString(reply.toString());
833+
} else {
834+
throw new ClosedSocketException("Channel was closed before message could be sent");
835+
}
832836
}
833837
catch(IOException e) {
834-
if(e instanceof ClosedChannelException) {
835-
throw (ClosedChannelException)e;
836-
} else if(e.getCause() instanceof ClosedChannelException) {
837-
throw (ClosedChannelException)e.getCause();
838-
}
838+
ClosedSocketException.filter(e); // Explicitly detect and re-throw ClosedChannelExceptions
839839
log.error("Could not send message", e);
840840
}
841841
}

0 commit comments

Comments
 (0)