cancel
Showing results for 
Search instead for 
Did you mean: 

The marriage of Web Socket and HANA Cloud

shofmann
Participant
0 Kudos

I'm trying to get Web Socket working on a Java Web Application, running on HANA Cloud (former NetWeaver Cloud).

I'm already able to establish a socket and keep it open. Also, on the SAP HANA Cloud local runtime it works perfectly!

However, on HANA Cloud the communication currently works only one-way (from server to client, but not from client to server). In my eyes, this is the last problem - anything else works perfectly fine.

To simplify things, I started with an easy implementation of WebSocket and haven't used any framework, yet.

Server-Side

On the server I created a "websocket" servlet which I mapped to a URL.

Mapping (in web.xml)

<servlet>

  <description></description>

  <display-name>WebSocket</display-name>

  <servlet-name>WebSocket</servlet-name>

  <servlet-class>projectName.WebSocket</servlet-class>

</servlet>

<servlet-mapping>

  <servlet-name>WebSocket</servlet-name>

  <url-pattern>/WebSocket</url-pattern>

  <url-pattern>/websocket</url-pattern>

</servlet-mapping>

WebSocket Servlet (WebSocket.java)

package projectName;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.nio.CharBuffer;

import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.MessageInbound;

import org.apache.catalina.websocket.StreamInbound;

import org.apache.catalina.websocket.WebSocketServlet;

import org.apache.catalina.websocket.WsOutbound;

/**

* Servlet implementation class WebSocket

*/

public class WebSocket extends WebSocketServlet {

  private static final long serialVersionUID = 1L;

    @Override

    public void init() throws ServletException {

        super.init();

    }

    @Override

    protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) {

        return new WebSocketMessageInbound();

    }

    private static final class WebSocketMessageInbound extends MessageInbound {

        private static final CopyOnWriteArraySet<WebSocketMessageInbound> connections = new CopyOnWriteArraySet<WebSocketMessageInbound>();

        @Override

        protected void onBinaryMessage(ByteBuffer message) throws IOException {

            throw new UnsupportedOperationException("Binary message not supported");

        }

        @Override

        protected void onTextMessage(CharBuffer message) throws IOException {

            broadcast(message.toString());

        }

        @Override

        protected void onOpen(WsOutbound outbound) {

            connections.add(this);

            broadcast("Client has opened a connection");

        }

        @Override

        protected void onClose(int status) {

            connections.remove(this);

            broadcast("Client has closed the connection");

        }

        private void broadcast(String message) {

            for(WebSocketMessageInbound client : connections) {

                try {

                    CharBuffer buffer = CharBuffer.wrap(message);

                    client.getWsOutbound().writeTextMessage(buffer);

                }

                catch (IOException e) {

                    System.err.println("Caught IOException: " + e.getMessage());

                }

            }

        }

    }

}

Client-Side

The client simply calls the url, in my case when I run it on local: http://localhost:8080/websocket.html and then JavaScript code is executed automatically.

HTML File (websocket.html)

<!DOCTYPE html>

<html>

    <head>

        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>

        <title>Websocket Test</title>

        <script>

        var connection = new WebSocket('ws://' + location.host + '/websocket');

        // When the connection is open, log it

        connection.onopen = function () {

            console.log('Client: Web Socket connection established');

        };

        // Log errors

        connection.onerror = function (error) {

            console.log('WebSocket Error: ' + error);

        };

        // Log messages from the server

        connection.onmessage = function (e) {

            console.log('Server: ' + e.data);

        };

        // Send a message to the server every 10 seconds

        function sendMessage() {

            var message = 'Hi from Client';

            connection.send(message);

            console.log("Client: " + message);

            setTimeout("sendMessage()", 10000);

        }

        setTimeout("sendMessage()", 5000);

        </script>

    </head>

    <body>

    </body>

</html>

What should happen

  1. The Javascript-Code in websocket.html is executed on the client side and tries to open a Web Socket with the server by calling ws://localhost:8080/websocket (line 9 in websocket.html)
  2. Once a connection is established the client will send periodically every 10 seconds a message to the server
  3. The server responds by just sending the clients message back to the client. Not very useful functionality, but a good way to check if the Web Socket is open and two-way communication works.
    • Additionally, if a new client connected to the server, the server tells this all clients which are currently having an open web socket connection (stored in connections, see line 35 in WebSocket.java) by sending a message via WebSocket to them.

What actually happens

On localhost (SAP HANA Cloud local runtime)

Everything works. Opening a Web Socket connection, sending a message to the server as well as vice versa.

Great! If there wouldn't be the problem with HANA Cloud...

On HANA Cloud

First a notice: When I deploy the solution to HANA Cloud I change the ws://... URL to wss://... since HANA opens a secure SSL/TLS connection.

If I run the same code on HANA Cloud I can open a connection and get also respond from the server that the Web Socket connection is opened. But then any further messages which I want to send to the server somehow don't get through.

Further analyzing

However, the WebSocket connection stays open. I realized that when I accessed the same URL from another device (Laptop, iPhone, doesn't matter). Then I got the message from the server that another Client has opened a connection as shown in the image above (as mentioned above, I implemented the functionality that if a client connects or disconnects the server tells this every other client). This is proof that the WebSocket connection stays definitely open.

I also checked if this is maybe a proxy-related problem. But I also get the same behavior when I try this on "public" internet without any proxy.

To isolate the problem I also checked if the onTextMessage method (line 43 in WebSocket.java) is called on the server when I send a message: On HANA Cloud the method never gets called.

My guess is, that either the message doesn't even get to the server, but since I don't know any way how to debug HANA Cloud I am not sure about that. Also the HTTP logs are not very useful in that case: Once a Web Socket connection is established client and server switch from HTTP to WebSocket, so this communication won't be recorded in the HTTP log anymore.

Another guess would be that the server somehow only accepts a special encoding but doesn't tell this the client on the handshake. So the server could receive messages from the client, but discards all the messages since the encoding is incorrect.

That's the point where I'm currently kind of stuck - but it feels like I'm close to get WebSocket running on HANA Cloud. Would be great if someone can help me.

Best regards,

Simon

View Entire Topic
Former Member
0 Kudos

Hi Simon,

The HANA Cloud currently does not support websocket traffic - any non-HTTP traffic to applications is filtered. The initial connection succeeds because the websocket handshake is done over HTTP - a GET is sent to which the server responds with 101 "Sitching Protocols" (for more information see http://en.wikipedia.org/wiki/WebSocket). After that any traffic over the connection is packaged as websocket frames, which the HANA Cloud infrastructure filters. That's why you don't receive any response from the server.

shofmann
Participant
0 Kudos

Hi Petar,

thanks for your reply!

So it seems the HANA Cloud infrastructure only filters inbound traffic. Because once a WebSocket connection is established it stays open and the server can continue sending messages via WebSocket (which definitely arrive on the client-side as shown above).

Is there any way to change the filter on HANA Cloud that also inbound WebSocket-traffic comes through? There are many use-cases for using WebSocket connections and I found some other posts here on SCN of users trying to get WebSocket running - so there is probably demand for WebSocket support on HANA Cloud.

Former Member
0 Kudos

Hi Simon,

I'm not able to answer your question as of how (or when) the filter can be disabled, but I've forwarded your question to some colleagues which work on the infrastructure, who should be able to answer you.

shofmann
Participant
0 Kudos

Hi Petar,

2 weeks have passed. Did you get any response from your colleagues so far?

Thanks in advance.

Former Member
0 Kudos

We will try to address this on our short to mid-term roadmap. I hope in about a month I would be able to provide an exact date and more details. I will post an update to this thread.