Hi Ernie,
It has been a little while since I tinkered around in this space (sorry I've been so Qpid quiet recently BTW, I'm working on another project that's turned into a bit of a time-sink), but the fact that you are using websockify rings a few alarm bells with me.

Not that there's anything wrong with websockify per se, it's just that from my recollection it makes use of websocket subprotocols

So specifically websockify expects the websocket subprotocol to be "binary" for binary websockets or "base64" for, well, base64. OTOH the AMQP spec expects the websocket subprotocol to be "AMQPWSB10"

There was a conversation around that back in December when Rafi had some problems with websockify and the JavaScript binding.

The most relevant mail in the thread is (hopefully) attached.

Basically it needed a slightly hacked websockify to default to binary and only explicitly check for base64 or alternatively some compile time (or run time) tweaks to the JavaScript to use binary instead of AMQPWSB10


Looking at the description below it looks like you've got it working, but I'm curious what you did because last time I played with websockify it didn't just work out of the box when using a proper AMQPWSB10 subprotocol.

Cheers,
Frase

On 14/07/15 19:55, Ernie Allen wrote:
-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviews.apache.org/r/36480/
-----------------------------------------------------------

Review request for qpid, Alan Conway, Ganesh Murthy, Kenneth Giusti, mick 
goulish, and Ted Ross.


Repository: qpid-dispatch


Description
-------

This modifies the schema by adding a console entity. In the console entity you 
can define the attributes needed to run a proxy server that translates 
websockets to tcp and also serves http file requests.

listener {
...
     name: proxy
...
}

console {
     listener: proxy
     dir:      /home/eallen/dispatch-svn/tools/websockify/
     home:     webapps
     proxy:    qdproxy
     wsport:   5673
}


Diffs
-----

   trunk/python/qpid_dispatch/management/qdrouter.json 1690252
   trunk/python/qpid_dispatch_internal/management/agent.py 1690252

Diff: https://reviews.apache.org/r/36480/diff/


Testing
-------

bin/test.sh passes all tests.
I replaced the nodejs proxy I was using with the new python/websockify server.
In the 6 router network, I changed A.conf and added a name to the listener and 
added a console section that runs the python proxy/server.

The web console retrieves all html/js/css files, connects and communicates to 
the router network through the proxy.


Thanks,

Ernie Allen



--- Begin Message ---

On 12/12/14 18:30, Rafael Schloming wrote:
Hmm, so I hacked websockify to ignore what is specifed in the protocols header and hard coded it first to use binary, and second to use base64. Neither option seemed to work.

Hi again Rafi,
My bet is that when you hacked Websockify you didn't update the response, my hack of websockify/websockify.py (do_websocket_handshake) looks like:

    def do_websocket_handshake(self, headers, path):
        h = self.headers = headers
        self.path = path

        prot = 'WebSocket-Protocol'
        protocols = h.get('Sec-'+prot, h.get(prot, '')).split(',')

        ver = h.get('Sec-WebSocket-Version')
        if ver:
            # HyBi/IETF version of the protocol

            # HyBi-07 report version 7
            # HyBi-08 - HyBi-12 report version 8
            # HyBi-13 reports version 13
            if ver in ['7', '8', '13']:
                self.version = "hybi-%02d" % int(ver)
            else:
                raise self.EClose('Unsupported protocol version %s' % ver)

            key = h['Sec-WebSocket-Key']

            # Choose binary unless the client explicityly asks for Base64
            if 'base64' in protocols:
                self.base64 = True
            else:
                self.base64 = False
#raise self.EClose("Client must support 'binary' or 'base64' protocol")

            # Generate the hash value for the accept header
            accept = b64encode(sha1(s2b(key + self.GUID)).digest())

            response = self.server_handshake_hybi % b2s(accept)
            if self.base64:
                response += "Sec-WebSocket-Protocol: base64\r\n"
            else:
response += "Sec-WebSocket-Protocol: " + ', '.join(protocols) + "\r\n"
            response += "\r\n"

        else:
            # Hixie version of the protocol (75 or 76)

            if h.get('key3'):
                trailer = self.gen_md5(h)
                pre = "Sec-"
                self.version = "hixie-76"
            else:
                trailer = ""
                pre = ""
                self.version = "hixie-75"

            # We only support base64 in Hixie era
            self.base64 = True

            response = self.server_handshake_hixie % (pre,
                    h['Origin'], pre, self.scheme, h['Host'], path)

            if 'base64' in protocols:
                response += "%sWebSocket-Protocol: base64\r\n" % pre
            else:
self.msg("Warning: client does not report 'base64' protocol support")
            response += "\r\n" + trailer

        return response




The changed bits are:

            # Choose binary unless the client explicitly asks for Base64
            if 'base64' in protocols:
                self.base64 = True
            else:
                self.base64 = False
#raise self.EClose("Client must support 'binary' or 'base64' protocol")

and

            if self.base64:
                response += "Sec-WebSocket-Protocol: base64\r\n"
            else:
response += "Sec-WebSocket-Protocol: " + ', '.join(protocols) + "\r\n"





BTW for info I also tried hacking the JavaScript binding CMakeLists.txt to remove the
-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\"

and that works too (emscripten defaults to 'binary' unless a WebSocket sub-protocol is specified, that's done mainly so Websockify works out of the box, 'cause Websockify is what's used on the emscripten tests). The relevant bits are in emscripten/src/settings.js:

// As well as being configurable at compile time via the "-s" option the WEBSOCKET_URL and WEBSOCKET_SUBPROTOCOL
// settings may configured at run time via the Module object e.g.
// Module['websocket'] = {subprotocol: 'base64, binary, text'};
// Module['websocket'] = {url: 'wss://', subprotocol: 'base64'};
// Run time configuration may be useful as it lets an application select multiple different services. var WEBSOCKET_URL = 'ws://'; // A string containing either a WebSocket URL prefix (ws:// or wss://) or a complete // RFC 6455 URL - "ws[s]:" "//" host [ ":" port ] path [ "?" query ]. // In the (default) case of only a prefix being specified the URL will be constructed from
                             // prefix + addr + ':' + port
// where addr and port are derived from the socket connect/bind/accept calls. var WEBSOCKET_SUBPROTOCOL = 'binary'; // A string containing a comma separated list of WebSocket subprotocols // as would be present in the Sec-WebSocket-Protocol header.




Less drastically than changing this at compile time it's also perfectly possible to do it at run time.
If you look in say send.js you'll see a line that looks like:

    var proton = require("qpid-proton");

if after that line you do:

proton['websocket']['subprotocol'] = 'binary';

That will make it work with an unhacked Websockify too, though as I mentioned yesterday by setting this to binary rather than AMQPWSB10 it will work with Websockify but not the Java Broker.


At least the last approach puts control firmly in your hands so you can make it configurable. Actually I've just this moment tried:

proton['websocket']['subprotocol'] = 'binary, AMQPWSB10';

and that actually works with WebSockify too, but I've not yet checked whether that would work with the Java Broker, if it does that might be worth changing the compile/link flag to (though I suspect that it would make it even more off-spec wrt. the AMQP JavaScript binding spec.).


proxy.js is tolerant to all these shenanigans though :-D I'd be the first to admit that it needs some work in the error handling department but it felt worth including 'cause it's pretty simple, is Node.js based (which is already needed to compile the JavaScript binding, so no extra dependencies), is Apache licensed.

HTH, and thanks for taking the time to have a play with the JavaScript binding.

Cheers,
Frase



--- End Message ---
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to