/* * Websock: high-performance binary WebSockets * Copyright (C) 2012 Joel Martin * Licensed under MPL 2.0 (see LICENSE.txt) * * Websock is similar to the standard WebSocket object but Websock * enables communication with raw TCP sockets (i.e. the binary stream) * via websockify. This is accomplished by base64 encoding the data * stream between Websock and websockify. * * Websock has built-in receive queue buffering; the message event * does not contain actual data but is simply a notification that * there is new data available. Several rQ* methods are available to * read binary data off of the receive queue. */ function Websock(){"use strict";this._websocket=null,this._rQi=0,this._rQlen=0,this._rQbufferSize=4194304,this._rQmax=this._rQbufferSize/8,this._rQ=null,this._sQbufferSize=10240,this._sQlen=0,this._sQ=null,this._mode="binary",this.maxBufferedAmount=200,this._eventHandlers={message:function(){},open:function(){},close:function(){},error:function(){}}}window.WebSocket&&!window.WEB_SOCKET_FORCE_FLASH?Websock_native=!0:window.MozWebSocket&&!window.WEB_SOCKET_FORCE_FLASH?(Websock_native=!0,window.WebSocket=window.MozWebSocket):Websock_native=!1,function(){"use strict";var e=function(){try{var e=new Uint8Array([1,2,3]);return String.fromCharCode.apply(null,e),function(e){return String.fromCharCode.apply(null,e)}}catch(e){return function(e){return String.fromCharCode.apply(null,Array.prototype.slice.call(e))}}}();Websock.prototype={get_sQ:function(){return this._sQ},get_rQ:function(){return this._rQ},get_rQi:function(){return this._rQi},set_rQi:function(e){this._rQi=e},rQlen:function(){return this._rQlen-this._rQi},rQpeek8:function(){return this._rQ[this._rQi]},rQshift8:function(){return this._rQ[this._rQi++]},rQskip8:function(){this._rQi++},rQskipBytes:function(e){this._rQi+=e},rQshift16:function(){return(this._rQ[this._rQi++]<<8)+this._rQ[this._rQi++]},rQshift32:function(){return(this._rQ[this._rQi++]<<24)+(this._rQ[this._rQi++]<<16)+(this._rQ[this._rQi++]<<8)+this._rQ[this._rQi++]},rQshiftStr:function(t){void 0===t&&(t=this.rQlen());var i=new Uint8Array(this._rQ.buffer,this._rQi,t);return this._rQi+=t,e(i)},rQshiftBytes:function(e){return void 0===e&&(e=this.rQlen()),this._rQi+=e,new Uint8Array(this._rQ.buffer,this._rQi-e,e)},rQshiftTo:function(e,t){void 0===t&&(t=this.rQlen()),e.set(new Uint8Array(this._rQ.buffer,this._rQi,t)),this._rQi+=t},rQwhole:function(){return new Uint8Array(this._rQ.buffer,0,this._rQlen)},rQslice:function(e,t){return t?new Uint8Array(this._rQ.buffer,this._rQi+e,t-e):new Uint8Array(this._rQ.buffer,this._rQi+e,this._rQlen-this._rQi-e)},rQwait:function(e,t,i){if(this._rQlen-this._rQi0&&this._websocket.readyState===WebSocket.OPEN&&(this._websocket.send(this._encode_message()),this._sQlen=0),!0):(Util.Info("Delaying send, bufferedAmount: "+this._websocket.bufferedAmount),!1)},send:function(e){return this._sQ.set(e,this._sQlen),this._sQlen+=e.length,this.flush()},send_string:function(e){this.send(e.split("").map(function(e){return e.charCodeAt(0)}))},off:function(e){this._eventHandlers[e]=function(){}},on:function(e,t){this._eventHandlers[e]=t},_allocate_buffers:function(){this._rQ=new Uint8Array(this._rQbufferSize),this._sQ=new Uint8Array(this._sQbufferSize)},init:function(e,t){this._allocate_buffers(),this._rQi=0,this._websocket=null;var i=!1;"Uint8Array"in window&&"set"in Uint8Array.prototype&&(i=!0);var r=!1;try{i&&("binaryType"in WebSocket.prototype||new WebSocket(t+"://.").binaryType)&&(Util.Info("Detected binaryType support in WebSockets"),r=!0)}catch(e){}if(void 0===e&&(e="binary"),Array.isArray(e)&&e.indexOf("binary")>-1&&(e="binary"),!r)throw new Error("noVNC no longer supports base64 WebSockets. Please use a browser which supports binary WebSockets.");if("binary"!=e)throw new Error("noVNC no longer supports base64 WebSockets. Please use the binary subprotocol instead.");return e},open:function(e,t){var i=e.match(/^([a-z]+):\/\//)[1];t=this.init(t,i),this._websocket=new WebSocket(e,t),t.indexOf("binary")>=0&&(this._websocket.binaryType="arraybuffer"),this._websocket.onmessage=this._recv_message.bind(this),this._websocket.onopen=function(){if(Util.Debug(">> WebSock.onopen"),this._websocket.protocol?(this._mode=this._websocket.protocol,Util.Info("Server choose sub-protocol: "+this._websocket.protocol)):(this._mode="binary",Util.Error("Server select no sub-protocol!: "+this._websocket.protocol)),"binary"!=this._mode)throw new Error("noVNC no longer supports base64 WebSockets. Please use the binary subprotocol instead.");this._eventHandlers.open(),Util.Debug("<< WebSock.onopen")}.bind(this),this._websocket.onclose=function(e){Util.Debug(">> WebSock.onclose"),this._eventHandlers.close(e),Util.Debug("<< WebSock.onclose")}.bind(this),this._websocket.onerror=function(e){Util.Debug(">> WebSock.onerror: "+e),this._eventHandlers.error(e),Util.Debug("<< WebSock.onerror: "+e)}.bind(this)},close:function(){this._websocket&&(this._websocket.readyState!==WebSocket.OPEN&&this._websocket.readyState!==WebSocket.CONNECTING||(Util.Info("Closing WebSocket connection"),this._websocket.close()),this._websocket.onmessage=function(e){})},_encode_message:function(){return new Uint8Array(this._sQ.buffer,0,this._sQlen)},_expand_compact_rQ:function(e){var t=e||this._rQlen-this._rQi>this._rQbufferSize/2;if(t&&(e?this._rQbufferSize=8*(this._rQlen-this._rQi+e):this._rQbufferSize*=2),this._rQbufferSize>41943040&&(this._rQbufferSize=41943040,this._rQbufferSize-this._rQlen-this._rQithis._rQbufferSize-this._rQlen&&this._expand_compact_rQ(t.length),this._rQ.set(t,this._rQlen),this._rQlen+=t.length},_recv_message:function(e){try{this._decode_message(e.data),this.rQlen()>0?(this._eventHandlers.message(),this._rQlen==this._rQi?(this._rQlen=0,this._rQi=0):this._rQlen>this._rQmax&&this._expand_compact_rQ()):Util.Debug("Ignoring empty message")}catch(e){var t="";e.name&&(t+="\n name: "+e.name+"\n",t+=" message: "+e.message+"\n"),void 0!==e.description&&(t+=" description: "+e.description+"\n"),void 0!==e.stack&&(t+=e.stack),t.length>0?Util.Error("recv_message, caught exception: "+t):Util.Error("recv_message, caught exception: "+e),void 0!==e.name?this._eventHandlers.error(e.name+": "+e.message):this._eventHandlers.error(e)}}}}();