-
-
Notifications
You must be signed in to change notification settings - Fork 750
Safari and WebSockets Issues
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.
First, let's take a look at Atmospehre's supported WebSockets Server
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 |
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. Server Sides Events, long-polling, http streaming, JSONP or polling can then be used in that scenario to reconnect. With Atmosphere JQuery PlugIn, the reconnect is done transparently, e.g the Safari 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);
}
All you need to define, in web.xml, the version you don't want to support
<description>Atmosphere Chat</description>
<display-name>Atmosphere Chat</display-name>
<servlet>
<description>AtmosphereServlet</description>
<servlet-name>AtmosphereServlet</servlet-name>
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
<init-param>
<param-name>org.atmosphere.websocket.bannedVersion</param-name>
<param-value>-1</param-value>
</init-param>
<!-- Use it with mvn jetty:run -->
<load-on-startup>0</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>WebSocket</filter-name>
<filter-class>org.atmosphere.websocket.WebSocketHandshakeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>WebSocket</filter-name>
<servlet-name>AtmosphereServlet</servlet-name>
</filter-mapping>
- Understanding Atmosphere
- Understanding @ManagedService
- Using javax.inject.Inject and javax.inject.PostConstruct annotation
- Understanding Atmosphere's Annotation
- Understanding AtmosphereResource
- Understanding AtmosphereHandler
- Understanding WebSocketHandler
- Understanding Broadcaster
- Understanding BroadcasterCache
- Understanding Meteor
- Understanding BroadcastFilter
- Understanding Atmosphere's Events Listeners
- Understanding AtmosphereInterceptor
- Configuring Atmosphere for Performance
- Understanding JavaScript functions
- Understanding AtmosphereResourceSession
- Improving Performance by using the PoolableBroadcasterFactory
- Using Atmosphere Jersey API
- Using Meteor API
- Using AtmosphereHandler API
- Using Socket.IO
- Using GWT
- Writing HTML5 Server-Sent Events
- Using STOMP protocol
- Streaming WebSocket messages
- Configuring Atmosphere's Classes Creation and Injection
- Using AtmosphereInterceptor to customize Atmosphere Framework
- Writing WebSocket sub protocol
- Configuring Atmosphere for the Cloud
- Injecting Atmosphere's Components in Jersey
- Sharing connection between Browser's windows and tabs
- Understanding AtmosphereResourceSession
- Manage installed services
- Server Side: javadoc API
- Server Side: atmosphere.xml and web.xml configuration
- Client Side: atmosphere.js API