3

I'm running a spring 3.1.2 backend on a weblogic 12.1.3 server. In order to accept websocket connections, my configurator as follows:

public class SpringConfigurator extends Configurator {
 private static final Logger LOGGER = LoggerFactory.make();
 private static final Map<String, Map<Class<?>, String>> cache = new ConcurrentHashMap<String, Map<Class<?>, String>>();
 private static final String MAGIC_STR = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
 private static final String NO_VALUE = ObjectUtils.identityToString(new Object());
 @SuppressWarnings("unchecked")
 @Override
 public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
 WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
 if (wac == null) {
 String message = "Failed to find the root WebApplicationContext. Was ContextLoaderListener not used?";
 LOGGER.error(message);
 throw new IllegalStateException(message);
 }
 String beanName = ClassUtils.getShortNameAsProperty(endpointClass);
 if (wac.containsBean(beanName)) {
 T endpoint = wac.getBean(beanName, endpointClass);
 if (LOGGER.isTraceEnabled()) {
 LOGGER.trace("Using @ServerEndpoint singleton " + endpoint);
 }
 return endpoint;
 }
 Component annot = AnnotationUtils.findAnnotation(endpointClass, Component.class);
 if ((annot != null) && wac.containsBean(annot.value())) {
 T endpoint = wac.getBean(annot.value(), endpointClass);
 if (LOGGER.isTraceEnabled()) {
 LOGGER.trace("Using @ServerEndpoint singleton " + endpoint);
 }
 return endpoint;
 }
 beanName = getBeanNameByType(wac, endpointClass);
 if (beanName != null) {
 return (T) wac.getBean(beanName);
 }
 if (LOGGER.isTraceEnabled()) {
 LOGGER.trace("Creating new @ServerEndpoint instance of type " + endpointClass);
 }
 return wac.getAutowireCapableBeanFactory().createBean(endpointClass);
 }
 // modifyHandshake() is called before getEndpointInstance()
 @Override
 public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
 super.modifyHandshake(sec, request, response);
 }
 private String getBeanNameByType(WebApplicationContext wac, Class<?> endpointClass) {
 String wacId = wac.getId();
 Map<Class<?>, String> beanNamesByType = cache.get(wacId);
 if (beanNamesByType == null) {
 beanNamesByType = new ConcurrentHashMap<Class<?>, String>();
 cache.put(wacId, beanNamesByType);
 }
 if (!beanNamesByType.containsKey(endpointClass)) {
 String[] names = wac.getBeanNamesForType(endpointClass);
 if (names.length == 1) {
 beanNamesByType.put(endpointClass, names[0]);
 } else {
 beanNamesByType.put(endpointClass, NO_VALUE);
 if (names.length > 1) {
 String message = "Found multiple @ServerEndpoint's of type " + endpointClass + ", names=" + names;
 LOGGER.error(message);
 throw new IllegalStateException(message);
 }
 }
 }
 String beanName = beanNamesByType.get(endpointClass);
 return NO_VALUE.equals(beanName) ? null : beanName;
 }
}

The problem is when I try to open websocket connection via a javascript client, it correctly generates response headers as I debugged this location:

@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
 super.modifyHandshake(sec, request, response);
}

But in client side it gives following error:

WebSocket connection to 'ws://localhost:7001/websocket' failed: Error during>WebSocket handshake: Invalid status line

In chrome developer tools the response seems as follows:

HTTP/0.9 200 OK

I think somehow http request does not upgrade to websocket connection.

I really appreciate any help regarding this issue.

asked Dec 15, 2015 at 18:53
2
  • I have the same problem but I'm using PHP ratchet as server, did you manage to solve the problem? Commented Mar 28, 2016 at 18:29
  • 2
    Hello, yes I've found that in my server configuration; filter chaining somehow corrupts websocket handshake response. I implemented a websocket filter to dispatch the request directly to the endpoint in order to bypass filter chaining request.getRequestDispatcher("/websocket").forward(httpServletRequest, httpServletResponse); It's not the best solution but it saved the day for now.. Commented Mar 30, 2016 at 7:51

1 Answer 1

1

I encountered exactly this issue today when testing http://showcase.omnifaces.org/push/socket on WebLogic 12.2.1.

Already at the first test attempt of the webapp, WebLogic throws the below exception when making a websocket connection:

java.lang.IllegalStateException: The async-support is disabled on this request: weblogic.servlet.internal.ServletRequest
Impl@6682044b[GET /omnifaces.push/counter?e6845a3a-26ed-4520-9824-63ffd85b24eb HTTP/1.1]
 at weblogic.servlet.internal.ServletRequestImpl.startAsync(ServletRequestImpl.java:1949)
 at weblogic.servlet.internal.ServletRequestImpl.startAsync(ServletRequestImpl.java:1925)
 at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:432)
 at weblogic.websocket.tyrus.TyrusServletFilter.doFilter(TyrusServletFilter.java:234)
 ...

It turns out that, on contrary to all other servers I tested, WebLogic's own TyrusServletFilter, which is responsible for handling websocket handshake requests, is internally installed after the filters provided via web.xml of the deployed webapp. The webapp shipped with a character encoding filter and a GZIP filter mapped on /*, so they were invoked before the websocket filter. This was strange at first sight, but I thought it is what it is, so I just added <async-supported>true</async-supported> to those webapp-provided filters so that the TyrusServletFilter can do its job.

However, when making a websocket connection, a JavaScript error in the client side occurred when a push message was being sent, exactly the one you faced:

WebSocket connection to 'ws://localhost:7001/omnifaces.push/counter?e6845a3a-26ed-4520-9824-63ffd85b24eb' failed: Error during WebSocket handshake: Invalid status line

It turns out that WebSockets just can't deal with GZIP responses. After disabling the GZIP filter, everything continued to work flawlessly.

The root problem is however that WebLogic should have installed its TyrusServletFilter before all webapp-provided filters. All other Java EE servers I ever have tested do this correctly. Your workaround of immediately dispatching and forwarding all websocket handshake requests to their target URL pattern, as mentioned in your comment on the question, is a good one. The alternative would be to reconfigure the web.xml-provided filters to not match websocket handshake requests anymore, e.g. by using a more specific URL pattern, or mapping to a specific servlet instead.

answered Jun 12, 2016 at 20:03
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.