Enable LWS_WITH_SERVER_STATUS option
[platform/upstream/libwebsockets.git] / test-server / lws-common.js
1 /*
2  * This section around grayOut came from here:
3  * http://www.codingforums.com/archive/index.php/t-151720.html
4  * Assumed public domain
5  *
6  * Init like this in your main html script, this also reapplies the gray
7  *
8  *    lws_gray_out(true,{'zindex':'499'});
9  *
10  * To remove the gray
11  *
12  *    lws_gray_out(false);
13  *
14  */
15
16 function lws_gray_out(vis, options) {
17         var options = options || {};
18         var zindex = options.zindex || 50;
19         var opacity = options.opacity || 70;
20         var opaque = (opacity / 100);
21         var bgcolor = options.bgcolor || '#000000';
22         var dark = document.getElementById('darkenScreenObject');
23
24         if (!dark) {
25                 var tbody = document.getElementsByTagName("body")[0];
26                 var tnode = document.createElement('div');
27                 tnode.style.position = 'absolute';
28                 tnode.style.top = '0px';
29                 tnode.style.left = '0px';
30                 tnode.style.overflow = 'hidden';
31                 tnode.style.display ='none';
32                 tnode.id = 'darkenScreenObject';
33                 tbody.appendChild(tnode);
34                 dark = document.getElementById('darkenScreenObject');
35         }
36         if (vis) {
37                 dark.style.opacity = opaque;
38                 dark.style.MozOpacity = opaque;
39                 dark.style.filter ='alpha(opacity='+opacity+')';
40                 dark.style.zIndex = zindex;
41                 dark.style.backgroundColor = bgcolor;
42                 dark.style.width = gsize(1);
43                 dark.style.height = gsize(0);
44                 dark.style.display ='block';
45                 addEvent(window, "resize",
46                         function() {
47                                 dark.style.height = gsize(0);
48                                 dark.style.width = gsize(1);
49                         }
50                 );
51         } else {
52                 dark.style.display = 'none';
53                 removeEvent(window, "resize",
54                         function() {
55                                 dark.style.height = gsize(0);
56                                 dark.style.width = gsize(1);
57                         }
58                 );
59         }
60 }
61
62 function gsize(ptype)
63 {
64         var h = document.compatMode == 'CSS1Compat' &&
65                 !window.opera ?
66                         document.documentElement.clientHeight :
67                                                 document.body.clientHeight;
68         var w = document.compatMode == 'CSS1Compat' &&
69                 !window.opera ? 
70                         document.documentElement.clientWidth :
71                                                 document.body.clientWidth;
72         if (document.body && 
73                     (document.body.scrollWidth || document.body.scrollHeight)) {
74                 var pageWidth = (w > (t = document.body.scrollWidth)) ?
75                                         ("" + w + "px") : ("" + (t) + "px");
76                 var pageHeight = (h > (t = document.body.scrollHeight)) ?
77                                         ("" + h + "px") : ("" + (t) + "px");
78         } else if (document.body.offsetWidth) {
79                 var pageWidth = (w > (t = document.body.offsetWidth)) ?
80                                         ("" + w + "px") : ("" + (t) + "px");
81                 var pageHeight =(h > (t = document.body.offsetHeight)) ?
82                                         ("" + h + "px") : ("" + (t) + "px");
83         } else {
84                 var pageWidth = '100%';
85                 var pageHeight = '100%';
86         }
87         return (ptype == 1) ? pageWidth : pageHeight;
88 }
89
90 function addEvent( obj, type, fn ) {
91         if ( obj.attachEvent ) {
92                 obj['e' + type + fn] = fn;
93                 obj[type+fn] = function() { obj['e' + type+fn]( window.event );}
94                 obj.attachEvent('on' + type, obj[type + fn]);
95         } else
96                 obj.addEventListener(type, fn, false);
97 }
98
99 function removeEvent( obj, type, fn ) {
100         if ( obj.detachEvent ) {
101                 obj.detachEvent('on' + type, obj[type + fn]);
102                 obj[type + fn] = null;
103         } else
104                 obj.removeEventListener(type, fn, false);
105 }
106
107 /*
108  * end of grayOut related stuff
109  */
110  
111 /*
112  * lws-meta helpers
113  */
114
115 var lws_meta_cmd = {
116         OPEN_SUBCHANNEL: 0x41,
117         /**< Client requests to open new subchannel
118          */
119         OPEN_RESULT: 0x42,
120         /**< Result of client request to open new subchannel */
121         CLOSE_NOT: 0x43,
122         CLOSE_RQ: 0x44,
123         /**< client requests to close a subchannel */
124         WRITE: 0x45,
125         /**< connection writes something to specific channel index */
126         RX: 0x46,
127 };
128
129 function new_ws(urlpath, protocol)
130 {
131         if (typeof MozWebSocket != "undefined")
132                 return new MozWebSocket(urlpath, protocol);
133
134         return new WebSocket(urlpath, protocol);
135 }
136
137 function lws_meta_ws() {
138         var real;
139         
140         var channel_id_to_child;
141         var pending_children;
142         var active_children;
143 }
144
145 function lws_meta_ws_child() {
146         var onopen;
147         var onmessage;
148         var onclose;
149         
150         var channel_id;
151         
152         var subprotocol;
153         var suburl;
154         var cookie;
155         
156         var extensions;
157         
158         var parent;
159 }
160
161 lws_meta_ws_child.prototype.send = function(data)
162 {
163
164         if (typeof data == "string") {
165                 data = String.fromCharCode(lws_meta_cmd.WRITE) +
166                         String.fromCharCode(this.channel_id) +
167                         data;
168                 
169                 return this.parent.real.send(data);
170         }
171         
172         {
173
174                 var ab = new Uint8Array(data.length + 2);
175
176                 ab[0] = lws_meta_cmd.WRITE;
177                 ab[1] = this.channel_id;
178                 ab.set(data, 2);
179         
180                 return this.parent.real.send(ab);
181         }
182 }
183
184 lws_meta_ws_child.prototype.close = function(close_code, close_string)
185 {
186         var pkt = new Uint8Array(129), m = 0, pkt1;
187         
188         pkt[m++] = lws_meta_cmd.CLOSE_RQ;
189         pkt[m++] = this.channel_id;
190         
191         pkt[m++] = close_string.length + 0x20;
192         
193         pkt[m++] = close_code / 256;
194         pkt[m++] = close_code % 256;
195         
196         for (i = 0; i < close_string.length; i++)
197                 pkt[m++] = close_string.charCodeAt(i);
198         
199         pkt1 = new Uint8Array(m);
200         for (n = 0; n < m; n++)
201                 pkt1[n] = pkt[n];
202                 
203         this.parent.real.send(pkt1.buffer);
204 }
205
206 /* make a real ws connection using lws_meta*/
207 lws_meta_ws.prototype.new_parent = function(urlpath)
208 {
209         var n, i, m = 0, pkt1;
210         
211         this.ordinal = 1;
212         this.pending_children = [];
213         this.active_children = [];
214         this.real = new_ws(urlpath, "lws-meta");
215         
216         this.real.binaryType = 'arraybuffer';
217         this.real.myparent = this;
218
219         this.real.onopen = function() {
220                 pkt = new Uint8Array(1024);
221                         var n, i, m = 0, pkt1;
222                 console.log("real open - pending children " + this.myparent.pending_children.length);
223                 for (n = 0; n < this.myparent.pending_children.length; n++) {
224                 
225                         var p = this.myparent.pending_children[n];
226                 
227                         pkt[m++] = lws_meta_cmd.OPEN_SUBCHANNEL;
228                         for (i = 0; i < p.subprotocol.length; i++)
229                                 pkt[m++] = p.subprotocol.charCodeAt(i);
230                         pkt[m++] = 0;
231                         for (i = 0; i < p.suburl.length; i++)
232                                 pkt[m++] = p.suburl.charCodeAt(i);
233                         pkt[m++] = 0;
234                         for (i = 0; i < p.cookie.length; i++)
235                                 pkt[m++] = p.cookie.charCodeAt(i);
236                         pkt[m++] = 0;
237                 }
238                 
239                 pkt1 = new Uint8Array(m);
240                 for (n = 0; n < m; n++)
241                         pkt1[n] = pkt[n];
242                 
243                 console.log(this.myparent.pending_children[0].subprotocol);
244                 console.log(pkt1);
245                 
246                 this.send(pkt1.buffer);
247         }
248
249
250         this.real.onmessage = function(msg) {
251         
252                 if (typeof msg.data != "string") {
253                         var ba = new Uint8Array(msg.data), n = 0;
254                         
255                         while (n < ba.length) {
256
257                                 switch (ba[n++]) {
258                                 case lws_meta_cmd.OPEN_RESULT:
259                                 {
260                                         var m = 0, cookie = "", protocol = "", ch = 0;
261                                         var ws = this.myparent;
262                                         /* cookie NUL
263                                          * channel index + 0x20
264                                          * protocol NUL
265                                          */
266                                          while (ba[n])
267                                                 cookie = cookie + String.fromCharCode(ba[n++]);
268                                          n++;
269                                          ch = ba[n++];
270                                          
271                                          while (ba[n])
272                                                 protocol = protocol + String.fromCharCode(ba[n++]);
273                                                 
274                                         console.log("open result " + cookie + " " + protocol + " " + ch + " pending len " + ws.pending_children.length);
275                                         
276                                         for (m = 0; m < ws.pending_children.length; m++) {
277                                                 if (ws.pending_children[m].cookie == cookie) {
278                                                         var newchild = ws.pending_children[m];
279                         
280                                                         /* found it */
281                                                         ws.pending_children[m].channel_id = ch;
282                                                         /* add to active children array */
283                                                         ws.active_children.push(ws.pending_children[m]);
284                                                         /* remove from pending children array */
285                                                         ws.pending_children.splice(m, 1);
286                                                         
287                                                         newchild.parent = ws;
288                                                         newchild.extensions = this.extensions;
289                                                         
290                                                         newchild.onopen();
291                                                         
292                                                         console.log("made active " + cookie);
293                                                         break;
294                                                 }
295                                         }
296                                         break;
297                                 }
298         
299                                 case lws_meta_cmd.CLOSE_NOT:
300                                 {
301                                         var code = 0, str = "", ch = 0, m, le;
302                                         var ba = new Uint8Array(msg.data);
303                                         /*
304                                          * BYTE: channel
305                                          * BYTE: MSB status code
306                                          * BYTE: LSB status code
307                                          * BYTES: rest of message is close status string
308                                          */
309                                          
310                                          ch = ba[n++];
311                                          le = ba[n++] - 0x20;
312                                          code = ba[n++] * 256;
313                                          code += ba[n++];
314                                          
315                                          while (le--)
316                                                 str += String.fromCharCode(ba[n++]);
317                                                 
318                                         console.log("channel id " + ch + " code " + code + " str " + str + " len " + str.length);
319                                                 
320                                         for (m = 0; m < this.myparent.active_children.length; m++)
321                                                 if (this.myparent.active_children[m].channel_id == ch) {
322                                                         var child = this.myparent.active_children[m];
323                                                         var ms = new CloseEvent("close", { code:code, reason:str } );
324                                                         
325                                                         /* reply with close ack */
326                                                         this.send(msg.data);
327                                                         
328                                                         if (child.onclose)
329                                                                 child.onclose(ms);
330                                                         
331                                                         this.myparent.active_children.splice(m, 1);
332                                                         break;
333                                                 }
334
335                                 }
336                                 } // switch
337                         }
338                 } else {
339                         if (msg.data.charCodeAt(0) == lws_meta_cmd.WRITE ) {
340                                 var ch = msg.data.charCodeAt(1), m, ms;
341                                 var ws = this.myparent, ms;
342                                                                 
343                                 for (m = 0; m < ws.active_children.length; m++) {
344                                         if (ws.active_children[m].channel_id == ch) {
345                                                 ms = new MessageEvent("WebSocket", { data: msg.data.substr(2, msg.data.length - 2) } );
346                                                 if (ws.active_children[m].onmessage)
347                                                         ws.active_children[m].onmessage(ms);
348                                                 break;
349                                         }
350                                 }
351                         }
352                 }
353         }
354         this.real.onclose = function() {
355                 var ws = this.myparent, m;
356                 for (m = 0; m < ws.active_children.length; m++) {
357                         var child = ws.active_children[m];
358                         var ms = new CloseEvent("close", { code:1000, reason:"parent closed" } );
359                         
360                         if (child.onclose)
361                                 child.onclose(ms);
362                 }
363         }
364
365 }
366
367
368
369 /* make a child connection using existing lws_meta real ws connection */
370 lws_meta_ws.prototype.new_ws = function(suburl, protocol)
371 {
372         var ch = new lws_meta_ws_child();
373         
374         ch.suburl = suburl;
375         ch.subprotocol = protocol;
376         ch.cookie = "C" + this.ordinal++;
377         
378         this.pending_children.push(ch);
379         
380         if (this.real.readyState == 1)
381                 this.real.onopen();
382         
383         return ch;
384 }
385
386
387 /*
388  * end of lws-meta helpers
389  */
390  
391 function lws_san(s)
392 {
393         if (s.search("<") != -1)
394                 return "invalid string";
395         
396         return s;
397 }