Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send and receive binary data over web sockets in Javascript?

It is possible to send and receive binary data over web sockets in Javascript? Could I, for example, implement an SSH client using web sockets?

like image 320
Chad Johnson Avatar asked Apr 23 '11 20:04

Chad Johnson


People also ask

Can WebSockets send binary data?

WebSockets support sending binary messages, too. To send binary data, one can use either Blob or ArrayBuffer object. Instead of calling the send method with string, you can simply pass an ArrayBuffer or a Blob .

Can WebSocket handle both text and binary data?

WebSocket enables bidirectional, message-oriented streaming of text and binary data between client and server. It is the closest API to a raw network socket in the browser.

What is WebSocket binary?

The WebSocket protocol allows to send arbitrary binary data (not even UTF-8 or Base-64 encoded) BUT that data are encapsulated in frames whose format is defined by WebSocket protocol (see RFC6455) and has nothing to do with SSH protocol.

Can WebSockets send and receive at the same time?

The key word in that definition is two-way: with WebSocket, both the client and the server can trigger communication with one another, and both can send messages, at the same time.


2 Answers

One good and safe way to send and receive binary data is with base64 or base128 (where 128 has just 1/7 overhead instead of 1/3).

Yes an SSH Client is possible.

A proof for this is that there are already a lot of solutions out there that run in common browsers, but most of them still needs a custom server side implementation. You can look here for more information: http://en.wikipedia.org/wiki/Web-based_SSH

like image 20
sra Avatar answered Sep 24 '22 12:09

sra


The next draft (hybi-07) of the WebSockets specification is being implemented in most browsers and it will add built-in binary support to the protocol and API.

However, until then, WebSockets payload is encoded as UTF-8. In order to send binary data you must use some way of encoding the binary data as UTF-8.

There are many options but here are two that I have used:

UTF-8:

You can actually encode a byte stream directly to UTF-8.

The python to encode and decode would look something like this:

from codecs import (utf_8_encode, utf_8_decode,                     latin_1_encode, latin_1_decode)  utf_8_encode(unicode(buf, 'latin-1'))[0]      # encode  latin_1_encode(utf_8_decode(utf8_buf)[0])[0]  # decode 

In Javascript:

chr = data.charCodeAt(N)  // to 'decode' at position N of the message  // Enocde array of bytes (0-255) to UTF-8 data = array.map(function (num) {     return String.fromCharCode(num); }).join(''); 

UTF-8 encode notes:

  • For binary data that is evenly distributed across value 0-255, then size of the payload is 50% larger than the raw binary data.

  • The Flash WebSockets emulator web-socket-js may have trouble with the encoding of 0 (zero).

Base 64:

In python:

from base64 import b64encode, b64decode  data = b64encode(buf)    # encode binary buffer to b64  buf = b64decode(data)    # decode b64 to binary buffer 

To encode and decode the messages on the Javascript side:

data = window.btoa(msg)  // Encode to base64  msg = window.atob(data)  // Decode base64 msg.charCodeAt(N)        // Read decode byte at N 

Base 64 notes:

  • Evenly distributed binary data (0-255) will be 33% larger than the raw data.

  • There is less python side overhead to base64 encoding than there is to UTF-8 encoding. However, there is a bit more Javascript side overhead to decoding base64 (UTF-8 doesn't need decoding in Javascript since the browser has already converted the UTF-8 to the Javascript native UTF-16).

  • Update: This assumes the binary data is encoded to a UTF-8 string as shown above with character values that range from 0-255. Specifically, window.atob does not support character values above 255. See this mozilla bug. The same limitation applies to Chrome.

websockify:

WebSockify is a proxy/bridge that allows a WebSockets capable browser to communicate with any arbitrary binary service. It was created to allow noVNC to communicate with existing VNC servers. websockify uses base64 encode/decode of the binary data and also provides a websock.js library for use in Javascript. The websock.js has an API similar to regular WebSocket but it is handles binary data transparently and is designed to communicate with websockify. Disclaimer: I created websockify and noVNC.

ssh client:

Technically you could implement a browser ssh client over WebSockets (and I've considered it), however, this will require doing SSH encryption and decryption in the browser which will be slow. Given that WebSockets has an encrypted WSS (TLS) mode, it probably makes more sense to do plain telnet over WebSocket WSS.

In fact, websockify includes an example telnet client.

You would launch websockify on HOSTNAME like this (telnetd is from krb5-telnetd):

sudo ./websockify 2023 --web . --wrap-mode=respawn -- telnetd -debug 2023 

Then navigate to http://HOSTNAME:2023/wstelnet.html?hostname=HOSTNAME&port=2023

See the websockify README for more information. To use WSS encryption you will need to create an SSL key as described on the noVNC advanced usage wiki page

like image 105
kanaka Avatar answered Sep 21 '22 12:09

kanaka