Safari’s WebSocket implementation and Java: Problematic!
The current Safari version (~5.1.5 … on OS X and iOS) implements an old version of the WebSockets specifications. This old version can cause major issues with Java WebServer in production. Here is some recommendations to workaround Safari. Important note: my observation are based on large deployments using the Atmosphere Framework.
First, let’s take a look at Java WebServers supporting WebSockets
| WebServers | Version | Specification | Safari Stability |
| Tomcat | 7.0.27 and up | hybi-13 and up | NOT SUPPORTED |
| Jetty | 7.0 to 7.4.5 | Up to hybi-12 | UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed. |
| Jetty | 7.5.x to 7.6.2 | Up to hybi-12 | UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed. |
| Jetty | 7.5.x to 7.6.2 | Up to hybi-13 | UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed. |
| Jetty | 8.x to 8.1.2 | Up to hybi-13 | UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed. |
| Jetty | 7.6.3 | All hybi version | STABLE |
| Jetty | 8.1.3 | All hybi version | STABLE |
| GlassFish | 3.1.1 | All hybi version | UNSTABLE: Suffer many API bugs |
| GlassFish | 3.1.2 | All hybi version | STABLE |
| NettoSphere (based on Netty Framework) | 1.x | All hybi version | STABLE |
My recommendation is if you need to put a WebSocket application in production, use Jetty 7.6.3 or 8.1.3. GlassFish is also a good server but much more heavyweight to use if you are planning to write pure WebSocket applications. NettoSphere is fairly new and until Atmosphere 1.0.0 is released, I’m not yet recommending it (yet!). Note that the Netty Framework’s WebSocket implementation can be considered a STABLE as well, but to run Atmosphere on top of it you need NettoSphere.
Now if you can’t any of the stable WebServer, you can still use WebSockets. All you need to do is to write a Servlet’s Filter that will detect the WebSocket version and force Safari to downgrade to another “transport” or communication channel. Server Sides Events, long-polling, http streaming, polling or JSONP can then be used to reconnect. You just need to implement the reconnect inside your websocket#onClose function. With Atmosphere JQuery PlugIn, the reconnect is done transparently, e./g no special code needed. The Atmosphere Filter looks like:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String draft = filterConfig
.getInitParameter(ApplicationConfig.WEB_SOCKET_BANNED_VERSION);
if (draft != null) {
bannedVersion = draft.split(",");
logger.debug("Blocked WebSocket Draft version {}", draft);
}
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest r = HttpServletRequest.class.cast(request);
if (Utils.webSocketEnabled(r)) {
int draft =r.getIntHeader("Sec-WebSocket-Version");
if (draft < 0) {
draft = r.getIntHeader("Sec-WebSocket-Draft");
}
if (bannedVersion != null) {
for (String s : bannedVersion) {
if (Integer.parseInt(s) == draft) {
HttpServletResponse.class.cast(response)
.sendError(501, "Websocket protocol not supported");
return;
}
}
}
}
chain.doFilter(request, response);
}
So if you aren’t using the Atmosphere Framework, make sure you have some sort of Filter than will block Safari from creating problem.
If you are planning to use WebSocket and Java, I strongly recommend you look at Atmosphere instead of using private native API and get stuck on a server forever. For more information, ping me on Twitter!


Safari implements the very first proposal/draft of WebSocket.
From the implementation Jetty sees coming from a Safari browser [1], it appears to be Draft-0 [2], with the awkward Hixie Bytes handshake.
There have been 76 Draft releases, plus the final RFC-6455 [3] spec, plus Errata [4] since Draft-0
I think its time for Safari to upgrade its implementation.
[1] http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/helper/SafariD00.java
[2] https://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-00
[3] https://tools.ietf.org/html/rfc6455
[4] http://www.rfc-editor.org/errata_search.php?rfc=6455
Same issue happens with older versions of Firefox which implement the older WebSocket versions.