add WebSocket to transports bouquet
authorMatteo Nastasi (mop) <nastasi@alternativeoutput.it>
Sun, 18 Aug 2013 15:05:09 +0000 (17:05 +0200)
committerMatteo Nastasi (mop) <nastasi@alternativeoutput.it>
Sun, 18 Aug 2013 15:05:27 +0000 (17:05 +0200)
TODO.txt
web/Obj/brisk.phh
web/Obj/sac-a-push.phh
web/Obj/transports.phh
web/Obj/user.phh
web/briskin5/index.php
web/commons.js
web/index.php
web/ws.php
web/xynt-streaming.js
web/xynt_test01.php

index 404a808..568cf21 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -4,12 +4,23 @@
   FEATURES |
  ----------+
    - WEBSOCKET TRANSPORT
-     . client (xynt_streaming.js)
-     . server (transport.phh)
+     DONE . fini of ws stream
+     DONE . reactivate compression
+     DONE . fix xynt_test01
+     DONE M2: brisk working
+     DONE . manage multiport apache config
+     DONE . manage headers correctly in sac-a-push
+     DONE . manage transport.close method where required
+     DONE . xynt_stream: manage fallback to multiple ports
+     DONE . manage fini for ws
+     POST . server: manage input data from clients
+     POST . manage ping/pong (seems not required)
+
+     DONE . client (xynt_streaming.js)
+     DONE . server (transport.phh)
+
+     DONE M1: xynt_test01.php working
 
-     M1: xynt_test01.php working
-
-     . manage headers correctly in sac-a-push
 
    - improved S
      . db update (add components, maybe single string)
index 707b20a..202113f 100644 (file)
@@ -2344,6 +2344,7 @@ class Room
 
           break;
       case "index_rd_ifra.php":
+          // $enc = 'plain';
           do {
               if (!isset($cookie['sess'])
                   || (($user = $this->get_user($cookie['sess'], $idx)) == FALSE)) {
@@ -2367,7 +2368,6 @@ class Room
 
               $content = "";
               $user->stream_init($s_a_p->rndstr, $enc, $header, $header_out, $content, $get, $post, $cookie);
-              
               $response = headers_render($header_out, -1).$user->chunked_content($content);
               $response_l = mb_strlen($response, "ASCII");
               
index 502670d..0ae856e 100644 (file)
@@ -221,6 +221,14 @@ function headers_render($header, $len)
     }
     else if (isset($header['HTTP-Response'])) {
         $s = sprintf("HTTP/1.1 %s\r\n", $header['HTTP-Response']);
+        foreach($header as $key => $value) {
+            if (strtolower($key) == "http-response")
+                continue;
+            $s .= sprintf("%s: %s\r\n", $key, $value);
+        }
+        if ($len >= 0) {
+            $s .= sprintf("Content-Length: %ld\r\n", $len);
+        }
     }
     else {
         $s = "HTTP/1.1 200 OK\r\n";
@@ -716,6 +724,10 @@ class Sac_a_push {
                                 if (isset($this->s2u[$id])) {
                                     // $user_a[$s2u[$id]]->disable();
                                     if ($this->s2u[$id]->rd_socket_get() != NULL) {
+                                        // try to send close frame (for websocket)
+                                        $clo = $this->s2u[$id]->stream_close();
+                                        $clo_l = mb_strlen($clo, "ASCII");
+                                        @fwrite($sock, $clo, $clo_l);
                                         $this->s2u[$id]->rd_socket_set(NULL);
                                     }
                                     unset($this->s2u[$id]);
@@ -849,7 +861,7 @@ class Sac_a_push {
                         // echo "SPIA: [".substr($response, 0, 60)."...]\n";
                         // echo "SPIA: [".$response."]\n";
                         $response_l = mb_strlen($response, "ASCII");
-                        $wret = @fwrite($sock, $response);
+                        $wret = @fwrite($sock, $response, $response_l);
                         if ($wret < $response_l) {
                             printf("TROUBLE WITH FWRITE: %d\n", $wret);
                             $user->rd_cache_set(mb_substr($response, $wret, $response_l - $wret, "ASCII"));
@@ -868,6 +880,9 @@ class Sac_a_push {
                         }
                         unset($this->socks[$id]);
                         unset($this->s2u[$id]);
+                        $clo = $user->stream_close();
+                        $clo_l = mb_strlen($clo, "ASCII");
+                        @fwrite($sock, $clo, $clo_l);
                         fclose($sock);
                         printf("CLOSE ON LOOP\n");
                     }
index 3b6e79c..5ebfec4 100644 (file)
@@ -3,7 +3,7 @@
  *  sac-a-push - Obj/transports.phh
  *
  *  Copyright (C) 2012 Matteo Nastasi
- *                          mailto: nastasi@alternativeoutput.it 
+ *                          mailto: nastasi@alternativeoutput.it
  *                                  matteo.nastasi@milug.org
  *                          web: http://www.alternativeoutput.it
  *
  *   Mac | x  |    |    |    |    |
  *
  *
+ *   WS  | IW | FF | Ch | Op | Ko | IE
+ * ------+----+----+----+----+----+----
+ *   Lnx |    |    |    |    |    |
+ *   Win |    |    |    |    |    |
+ *   Mac |    |    |    |    |    |
+ *
+ *
  *   XHR | IW | FF | Ch | Op | Ko | IE
  * ------+----+----+----+----+----+----
  *   Lnx | Y  |    | ^D |    | Y  | x
  *
  */
 
-
 class Transport_template {
 
     function Transport_template() {
     }
 
     // return string value is appended to the content of the returned page
+    // return FALSE if fails
+    // check with '===' operator to disambiguation between "" and FALSE return value
     function init($enc, $header, &$header_out, $init_string, $base, $step)
     {
     }
 
-    static function fini($init_string, $base, $blockerr)
+    function close()
     {
     }
 
@@ -74,114 +82,395 @@ class Transport_template {
     function is_chunked()
     {
     }
+
+    // return string to add to the stream to perform something to the engine
+    static function fini($init_string, $base, $blockerr)
+    {
+        return "";
+    }
 }
 
 class Transport_websocket {
-    $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+    protected $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
 
     function Transport_websocket() {
+        $this->headerOriginRequired                 = false;
+        $this->headerSecWebSocketProtocolRequired   = false;
+        $this->headerSecWebSocketExtensionsRequired = false;
+
+        $this->sendingContinuous = false;
+       $this->sendingContinuous = false;
+       $this->partialMessage = "";
+
+       $this->hasSentClose = false;
     }
 
-    protected function doHandshake($user, $buffer) {
-        $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
-        $headers = array();
-        $lines = explode("\n",$buffer);
-        foreach ($lines as $line) {
-            if (strpos($line,":") !== false) {
-                $header = explode(":",$line,2);
-                $headers[strtolower(trim($header[0]))] = trim($header[1]);
-            } else if (stripos($line,"get ") !== false) {
-                preg_match("/GET (.*) HTTP/i", $buffer, $reqResource);
-                $headers['get'] = trim($reqResource[1]);
+    protected function extractHeaders($message) {
+        $header = array('fin'     => $message[0] & chr(128),
+                        'rsv1'    => $message[0] & chr(64),
+                        'rsv2'    => $message[0] & chr(32),
+                        'rsv3'    => $message[0] & chr(16),
+                        'opcode'  => ord($message[0]) & 15,
+                        'hasmask' => $message[1] & chr(128),
+                        'length'  => 0,
+                        'mask'    => "");
+        $header['length'] = (ord($message[1]) >= 128) ? ord($message[1]) - 128 : ord($message[1]);
+
+        if ($header['length'] == 126) {
+            if ($header['hasmask']) {
+                $header['mask'] = $message[4] . $message[5] . $message[6] . $message[7];
             }
+            $header['length'] = ord($message[2]) * 256
+                + ord($message[3]);
+        } elseif ($header['length'] == 127) {
+            if ($header['hasmask']) {
+                $header['mask'] = $message[10] . $message[11] . $message[12] . $message[13];
+            }
+            $header['length'] = ord($message[2]) * 65536 * 65536 * 65536 * 256
+                + ord($message[3]) * 65536 * 65536 * 65536
+                + ord($message[4]) * 65536 * 65536 * 256
+                + ord($message[5]) * 65536 * 65536
+                + ord($message[6]) * 65536 * 256
+                + ord($message[7]) * 65536
+                + ord($message[8]) * 256
+                + ord($message[9]);
+        } elseif ($header['hasmask']) {
+            $header['mask'] = $message[2] . $message[3] . $message[4] . $message[5];
+        }
+        //echo $this->strtohex($message);
+        //$this->printHeaders($header);
+        return $header;
+    }
+
+    protected function extractPayload($message,$headers) {
+        $offset = 2;
+        if ($headers['hasmask']) {
+            $offset += 4;
         }
-        if (isset($headers['get'])) {
-            $user->requestedResource = $headers['get'];
+        if ($headers['length'] > 65535) {
+            $offset += 8;
+        } elseif ($headers['length'] > 125) {
+            $offset += 2;
+        }
+        return substr($message,$offset);
+    }
+
+    protected function applyMask($headers,$payload) {
+        $effectiveMask = "";
+        if ($headers['hasmask']) {
+            $mask = $headers['mask'];
         } else {
-            // todo: fail the connection
-            $handshakeResponse = "HTTP/1.1 405 Method Not Allowed\r\n\r\n";                    
+            return $payload;
         }
-        if (!isset($headers['host']) || !$this->checkHost($headers['host'])) {
-            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+
+        while (mb_strlen($effectiveMask, "ASCII") < mb_strlen($payload, "ASCII")) {
+            $effectiveMask .= $mask;
         }
-        if (!isset($headers['upgrade']) || strtolower($headers['upgrade']) != 'websocket') {
-            $handshakeResponse = "HTTP/1.1 400 Bad Request";
-        } 
-        if (!isset($headers['connection']) || strpos(strtolower($headers['connection']), 'upgrade') === FALSE) {
-            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+        while (mb_strlen($effectiveMask, "ASCII") > mb_strlen($payload, "ASCII")) {
+            $effectiveMask = substr($effectiveMask,0,-1);
         }
-        if (!isset($headers['sec-websocket-key'])) {
-            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+        return $effectiveMask ^ $payload;
+    }
+
+    protected function checkRSVBits($headers,$user) { // override this method if you are using an extension where the RSV bits are used.
+        if (ord($headers['rsv1']) + ord($headers['rsv2']) + ord($headers['rsv3']) > 0) {
+            //$this->disconnect($user); // todo: fail connection
+            return true;
+        }
+        return false;
+    }
+
+    protected function strtohex($str) {
+        $strout = "";
+        for ($i = 0; $i < mb_strlen($str, "ASCII"); $i++) {
+            $strout .= (ord($str[$i])<16) ? "0" . dechex(ord($str[$i])) : dechex(ord($str[$i]));
+            $strout .= " ";
+            if ($i%32 == 7) {
+                $strout .= ": ";
+            }
+            if ($i%32 == 15) {
+                $strout .= ": ";
+            }
+            if ($i%32 == 23) {
+                $strout .= ": ";
+            }
+            if ($i%32 == 31) {
+                $strout .= "\n";
+            }
+        }
+        return $strout . "\n";
+    }
+
+    function chunk($step, $cont)
+    {
+        return $this->frame('@BEGIN@'.$cont.'@END@'); // , 'text', TRUE);
+    }
+
+    protected function frame($message, $messageType='text', $messageContinues=false) {
+        switch ($messageType) {
+        case 'continuous':
+            $b1 = 0;
+            break;
+        case 'text':
+            $b1 = ($this->sendingContinuous) ? 0 : 1;
+            break;
+        case 'binary':
+            $b1 = ($this->sendingContinuous) ? 0 : 2;
+            break;
+        case 'close':
+            $b1 = 8;
+            break;
+        case 'ping':
+            $b1 = 9;
+            break;
+        case 'pong':
+            $b1 = 10;
+            break;
+        }
+        if ($messageContinues) {
+            $this->sendingContinuous = true;
         } else {
-            
+            $b1 += 128;
+            $this->sendingContinuous = false;
         }
-        if (!isset($headers['sec-websocket-version']) || strtolower($headers['sec-websocket-version']) != 13) {
-            $handshakeResponse = "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13";
+
+        $length = mb_strlen($message, "ASCII");
+        $lengthField = "";
+        if ($length < 126) {
+            $b2 = $length;
+        } elseif ($length <= 65536) {
+            $b2 = 126;
+            $hexLength = dechex($length);
+            //$this->stdout("Hex Length: $hexLength");
+            if (mb_strlen($hexLength, "ASCII")%2 == 1) {
+                $hexLength = '0' . $hexLength;
+            }
+            $n = mb_strlen($hexLength, "ASCII") - 2;
+
+            for ($i = $n; $i >= 0; $i=$i-2) {
+                $lengthField = chr(hexdec(substr($hexLength, $i, 2))) . $lengthField;
+            }
+            while (mb_strlen($lengthField, "ASCII") < 2) {
+                $lengthField = chr(0) . $lengthField;
+            }
+        } else {
+            $b2 = 127;
+            $hexLength = dechex($length);
+            if (mb_strlen($hexLength, "ASCII")%2 == 1) {
+                $hexLength = '0' . $hexLength;
+            }
+            $n = mb_strlen($hexLength, "ASCII") - 2;
+
+            for ($i = $n; $i >= 0; $i=$i-2) {
+                $lengthField = chr(hexdec(substr($hexLength, $i, 2))) . $lengthField;
+            }
+            while (mb_strlen($lengthField, "ASCII") < 8) {
+                $lengthField = chr(0) . $lengthField;
+            }
         }
-        if (($this->headerOriginRequired && !isset($headers['origin']) ) || ($this->headerOriginRequired && !$this->checkOrigin($headers['origin']))) {
-            $handshakeResponse = "HTTP/1.1 403 Forbidden";
+
+        return chr($b1) . chr($b2) . $lengthField . $message;
+    }
+
+    protected function deframe($message) {
+        //echo $this->strtohex($message);
+        $headers = $this->extractHeaders($message);
+        $pongReply = false;
+        $willClose = false;
+        switch($headers['opcode']) {
+        case 0:
+        case 1:
+        case 2:
+            break;
+        case 8:
+            // todo: close the connection
+            $this->hasSentClose = true;
+            return "";
+        case 9:
+            $pongReply = true;
+        case 10:
+            break;
+        default:
+            //$this->disconnect($user); // todo: fail connection
+            $willClose = true;
+            break;
         }
-        if (($this->headerSecWebSocketProtocolRequired && !isset($headers['sec-websocket-protocol'])) || ($this->headerSecWebSocketProtocolRequired && !$this->checkWebsocProtocol($header['sec-websocket-protocol']))) {
-            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+
+        if ($this->handlingPartialPacket) {
+            $message = $this->partialBuffer . $message;
+            $this->handlingPartialPacket = false;
+            return $this->deframe($message);
         }
-        if (($this->headerSecWebSocketExtensionsRequired && !isset($headers['sec-websocket-extensions'])) || ($this->headerSecWebSocketExtensionsRequired && !$this->checkWebsocExtensions($header['sec-websocket-extensions']))) {
-            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+
+        if ($this->checkRSVBits($headers,$this)) {
+            return false;
         }
-        
-        // Done verifying the _required_ headers and optionally required headers.
-        
-        if (isset($handshakeResponse)) {
-            socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse));
-            $this->disconnect($user->socket);
+
+        if ($willClose) {
+            // todo: fail the connection
             return false;
         }
-        
-        $user->headers = $headers;
-        $user->handshake = $buffer;
-        
-        $webSocketKeyHash = sha1($headers['sec-websocket-key'] . $magicGUID);
-        
-        $rawToken = "";
-        for ($i = 0; $i < 20; $i++) {
-            $rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2)));
+
+        $payload = $this->partialMessage . $this->extractPayload($message,$headers);
+
+        if ($pongReply) {
+            $reply = $this->frame($payload,$this,'pong');
+            // TODO FIXME ALL socket_write management
+            socket_write($user->socket,$reply,mb_strlen($reply, "ASCII"));
+            return false;
+        }
+        if (extension_loaded('mbstring')) {
+            if ($headers['length'] > mb_strlen($payload, "ASCII")) {
+                $this->handlingPartialPacket = true;
+                $this->partialBuffer = $message;
+                return false;
+            }
+        } else {
+            if ($headers['length'] > mb_strlen($payload, "ASCII")) {
+                $this->handlingPartialPacket = true;
+                $this->partialBuffer = $message;
+                return false;
+            }
+        }
+
+        $payload = $this->applyMask($headers,$payload);
+
+        if ($headers['fin']) {
+            $this->partialMessage = "";
+            return $payload;
         }
-        $handshakeToken = base64_encode($rawToken) . "\r\n";
-        
-        $subProtocol = (isset($headers['sec-websocket-protocol'])) ? $this->processProtocol($headers['sec-websocket-protocol']) : "";
-        $extensions = (isset($headers['sec-websocket-extensions'])) ? $this->processExtensions($headers['sec-websocket-extensions']) : "";
-        
-        $handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken$subProtocol$extensions\r\n";
-        socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse));
-        $this->connected($user);
+        $this->partialMessage = $payload;
+        return false;
     }
-    
 
-    function init($enc, $header, &$header_out, $init_string, $base, $step)
+
+    protected function checkHost($hostName) {
+        return true; // Override and return false if the host is not one that you would expect.
+        // Ex: You only want to accept hosts from the my-domain.com domain,
+        // but you receive a host from malicious-site.com instead.
+    }
+
+    protected function checkOrigin($origin) {
+        return true; // Override and return false if the origin is not one that you would expect.
+    }
+
+    protected function checkWebsocProtocol($protocol) {
+        return true; // Override and return false if a protocol is not found that you would expect.
+    }
+
+    protected function checkWebsocExtensions($extensions) {
+        return true; // Override and return false if an extension is not found that you would expect.
+    }
+
+    protected function processProtocol($protocol) {
+        return ""; // return either "Sec-WebSocket-Protocol: SelectedProtocolFromClientList\r\n" or return an empty string.
+        // The carriage return/newline combo must appear at the end of a non-empty string, and must not
+        // appear at the beginning of the string nor in an otherwise empty string, or it will be considered part of
+        // the response body, which will trigger an error in the client as it will not be formatted correctly.
+    }
+
+    protected function processExtensions($extensions) {
+        return ""; // return either "Sec-WebSocket-Extensions: SelectedExtensions\r\n" or return an empty string.
+    }
+
+    function init($enc, $headers, &$headers_out, $init_string, $base, $step)
     {
-        
+        if (0) { // TODO: what is ?
+            if (isset($headers['get'])) {
+                $this->requestedResource = $headers['get'];
+            } else {
+                // todo: fail the connection
+                $headers_out['HTTP-Response'] = "405 Method Not Allowed";
+            }
+        }
 
+        if (!isset($headers['Host']) || !$this->checkHost($headers['Host'])) {
+            $headers_out['HTTP-Response'] = "400 Bad Request";
+        }
+        if (!isset($headers['Upgrade']) || strtolower($headers['Upgrade']) != 'websocket') {
+            $headers_out['HTTP-Response'] = "400 Bad Request";
+        }
+        if (!isset($headers['Connection']) || strpos(strtolower($headers['Connection']), 'upgrade') === FALSE) {
+            $headers_out['HTTP-Response'] = "400 Bad Request";
+        }
+        if (!isset($headers['Sec-Websocket-Key'])) {
+            $headers_out['HTTP-Response'] = "400 Bad Request";
+        } else {
+        }
 
+        if (!isset($headers['Sec-Websocket-Version']) || strtolower($headers['Sec-Websocket-Version']) != 13) {
+            $headers_out['HTTP-Response'] = "426 Upgrade Required";
+            $headers_out['Sec-WebSocketVersion'] = "13";
+        }
+        if ( ($this->headerOriginRequired && !isset($headers['Origin']) )
+             || ($this->headerOriginRequired && !$this->checkOrigin($headers['Origin'])) ) {
+            $headers_out['HTTP-Response'] = "403 Forbidden";
+        }
+        if ( ($this->headerSecWebSocketProtocolRequired && !isset($headers['Sec-Websocket-Protocol']))
+             || ($this->headerSecWebSocketProtocolRequired &&
+                 !$this->checkWebsocProtocol($headers['Sec-Websocket-Protocol']))) {
+            $headers_out['HTTP-Response'] = "400 Bad Request";
+        }
+        if ( ($this->headerSecWebSocketExtensionsRequired  && !isset($headers['Sec-Websocket-Extensions']))
+             || ($this->headerSecWebSocketExtensionsRequired &&
+                 !$this->checkWebsocExtensions($headers['Sec-Websocket-Extensions'])) ) {
+            $headers_out['HTTP-Response'] = "400 Bad Request";
+        }
 
-        $ret = sprintf("@BEGIN@ /* %s */ @END@", $init_string);
-        if ($enc != 'plain')
-            $header_out['Content-Encoding'] = $enc;
-        $header_out['Cache-Control'] = 'no-cache, must-revalidate';     // HTTP/1.1
-        $header_out['Expires']       = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past
-        $header_out['Content-type']  = 'application/xml; charset="utf-8"';
+        if (isset($headers_out['HTTP-Response'])) {
+            // TODO: check return management
+            return (FALSE);
+        }
 
-        return ($ret);
+        // TODO: verify both variables
+        // here there is a change of the socket status from start to handshaked
+        // th headers are saved too but without any further access so we skip it
+
+
+
+        $inno = 'x3JJHMbDL1EzLkh9GBhXDw==';
+        $outo = sha1($inno . $this->magicGUID);
+        $rawToken = "";
+        for ($i = 0; $i < 20; $i++) {
+            $rawToken .= chr(hexdec(substr($outo,$i*2, 2)));
+        }
+
+        $outo = base64_encode($rawToken);
+
+        $webSocketKeyHash = sha1($headers['Sec-Websocket-Key'] . $this->magicGUID);
+        $rawToken = "";
+        for ($i = 0; $i < 20; $i++) {
+            $rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2)));
+        }
+        $handshakeToken = base64_encode($rawToken);
+        $subProtocol = (isset($headers['Sec-Websocket-Protocol'])) ?
+            $this->processProtocol($headers['Sec-Websocket-Protocol']) : "";
+        $extensions = (isset($headers['Sec-Websocket-Extensions'])) ?
+            $this->processExtensions($headers['Sec-Websocket-Extensions']) : "";
+
+        $headers_out['HTTP-Response'] = "101 Switching Protocols";
+        $headers_out['Upgrade']       = 'websocket';
+        $headers_out['Connection']    = 'Upgrade';
+        $headers_out['Sec-WebSocket-Accept'] = "$handshakeToken$subProtocol$extensions";
+
+        return ("");
+    }
+
+    static function close()
+    {
+        return(chr(0x88).chr(0x02).chr(0xe8).chr(0x03));
     }
 
     static function fini($init_string, $base, $blockerr)
     {
-        return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@',  ($blockerr ? 'xstm.stop(); ' : ''), $base));
-        return ("");
+        return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@',  ($blockerr ? 'xstm.stop(); ' : ''), $base).self::close());
     }
 
-    function chunk($step, $cont)
+    function is_chunked()
     {
-        return ("@BEGIN@".$cont."@END@");
+        return FALSE;
     }
+
 }
 
 class Transport_xhr {
@@ -201,6 +490,11 @@ class Transport_xhr {
         return ($ret);
     }
 
+    function close()
+    {
+        return "";
+    }
+
     static function fini($init_string, $base, $blockerr)
     {
         return (sprintf('@BEGIN@ %s window.onbeforeunload = null; window.onunload = null; document.location.assign("%sindex.php"); @END@',  ($blockerr ? 'xstm.stop(); ' : ''), $base));
@@ -232,7 +526,7 @@ class Transport_iframe {
         $header_out['Cache-Control'] = 'no-cache, must-revalidate';     // HTTP/1.1
         $header_out['Expires']       = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Date in the past
         $header_out['Content-type']  = 'text/html; charset="utf-8"';
-        
+
         $ret .= sprintf("<html>
 <head>
 <script type=\"text/javascript\" src=\"%scommons.js\"></script>
@@ -243,7 +537,7 @@ var xynt_streaming = \"ready\";", $base, $base);
             $ret .= sprintf("last_clean = %d;\n", ($step-1));
         $ret .= sprintf("
 window.onload = function () { try { if (xynt_streaming != \"ready\") { xynt_streaming.transp.stopped = true; } } catch(e) { /* console.log(\"catcha\"); */ } };
-</script> 
+</script>
 </head>
 <body>");
         $ret .= sprintf("<!-- \n%s -->\n", $init_string);
@@ -251,6 +545,11 @@ window.onload = function () { try { if (xynt_streaming != \"ready\") { xynt_stre
         return ($ret);
     }
 
+    function close()
+    {
+        return "";
+    }
+
     static function fini($init_string, $base, $blockerr)
     {
         $ret = "";
@@ -301,7 +600,10 @@ class Transport {
 
     static function create($transp)
     {
-        if ($transp == 'xhr') {
+        if ($transp == 'websocket') {
+            return new Transport_websocket();
+        }
+        else if ($transp == 'xhr') {
             return new Transport_xhr();
         }
         else if ($transp == 'htmlfile') {
@@ -313,7 +615,7 @@ class Transport {
     }
     static function gettype($transp)
     {
-        if ($transp == 'xhr' || $transp == 'htmlfile') {
+        if ($transp == 'websocket' || $transp == 'xhr' || $transp == 'htmlfile') {
             return "Transport_".$transp;
         }
         else {
index 55a3a75..2caf30a 100644 (file)
@@ -720,7 +720,13 @@ function stream_init($init_string, $enc, $header, &$header_out, &$body, $get, $p
     
     $this->rd_data_set($curtime, $transp, $enc, $stat, $subst, $step, $from);
     
-    $body .= $this->rd_transp->init($enc, $header, &$header_out, $init_string, self::base_get(), $this->rd_scristp);
+    $ret = $this->rd_transp->init($enc, $header, &$header_out, $init_string, self::base_get(), $this->rd_scristp);
+
+    if ($ret === FALSE) {
+        return FALSE;
+    }
+
+    $body .= $ret;
 
     return TRUE;
   }
@@ -760,6 +766,11 @@ function stream_keepalive($with_ping)
     return ($this->rd_transp->chunk( $this->rd_scristp++, ($with_ping ? "act_ping();" : NULL)));
 }
 
+function stream_close()
+{
+    return ($this->rd_transp->close());
+}
+
 static function base_get()
 {
     $c = get_called_class();
@@ -803,7 +814,7 @@ function chunked_content($content)
         return (sprintf("%X\r\n", $cont_comp_l).$cont_comp."\r\n");
     }
     else {
-        return $content;
+        return $cont_comp;
     }
 }
 
index af20289..15b449f 100644 (file)
@@ -116,7 +116,7 @@ window.onload = function() {
   preferences_update();
 
   sess = "<?php echo "$sess"; ?>";
-  xstm = new xynt_streaming(window, "<?php echo "$transp_type"; ?>", null /* console */, gst, 'table_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);});
+  xstm = new xynt_streaming(window, "<?php echo "$transp_type"; ?>", 80, 2, null /* console */, gst, 'table_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);});
   xstm.hbit_set(heartbit);
   
   window.onbeforeunload = onbeforeunload_cb;  
index 4cf95dc..3021613 100644 (file)
@@ -1195,7 +1195,7 @@ function url_complete(parent, url)
     }
 
     // alert("host: ["+host+"]  path: ["+path+"]");
-    if (url.substring(0,6) == 'http:/' || url.substring(0,7) == 'https:/') {
+    if (url.substring(0,6) == 'http:/' || url.substring(0,7) == 'https:/' || url.substring(0,4) == 'ws:/') {
         return (url);
     }
     else if (url.substring(0,1) == '/') {
index 0b3076a..a3d283f 100644 (file)
@@ -3,7 +3,7 @@
  *  brisk - index.php
  *
  *  Copyright (C) 2006-2012 Matteo Nastasi
- *                          mailto: nastasi@alternativeoutput.it 
+ *                          mailto: nastasi@alternativeoutput.it
  *                                  matteo.nastasi@milug.org
  *                          web: http://www.alternativeoutput.it
  *
@@ -96,7 +96,7 @@ $mlang_room = array( 'userpasserr'  => array('it' => 'Utente e/o password errati
                                              'en' => 'mop'),
                      'st_visch_desc'  => array('it' => 'vischio',
                                              'en' => 'mop'),
-                     
+
                      'tit_ticker'   => array('it' => 'scrivi un invito al tavolo e clicca',
                                              'en' => 'write an invitation at the table and click'),
                      'itm_warr'     => array('it' => 'garantisci',
@@ -243,13 +243,13 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
 {
     GLOBAL $G_with_donors, $G_donors_cur, $G_donors_all;
     GLOBAL $G_with_topbanner, $G_topbanner, $G_is_local;
-    GLOBAL $G_with_sidebanner, $G_sidebanner; 
-    GLOBAL $G_with_sidebanner2, $G_sidebanner2; 
+    GLOBAL $G_with_sidebanner, $G_sidebanner;
+    GLOBAL $G_with_sidebanner2, $G_sidebanner2;
     GLOBAL $G_with_poll;
     GLOBAL $G_lang, $G_lng, $mlang_room;
     GLOBAL $BRISK_SHOWHTML, $BRISK_DEBUG, $_SERVER;
 
-    if (($sess = gpcs_var('sess', $get, $post, $cookie)) === FALSE) 
+    if (($sess = gpcs_var('sess', $get, $post, $cookie)) === FALSE)
         $sess = "";
     if (($name = gpcs_var('name', $get, $post, $cookie)) === FALSE)
         unset($name);
@@ -270,14 +270,14 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
   $tables = "";
   $standup = "";
   $ACTION = "login";
-  
+
   if (isset($BRISK_SHOWHTML) == FALSE) {
       $is_table = FALSE;
       log_main("lock Room");
       $curtime = time();
-      
+
       /* Actions */
-      
+
       if (validate_sess($sess)) {
           log_main("pre garbage_manager UNO");
           $room->garbage_manager(TRUE);
@@ -294,17 +294,15 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
               }
               $ACTION = "room";
           }
-          
       }
-      
+
       if ($ACTION == "login" && isset($name)) {
-          
           log_main("pre garbage_manager DUE");
-          
+
           if (isset($pass_private) == FALSE) {
               $pass_private = FALSE;
           }
-          
+
           $room->garbage_manager(TRUE);
           /* try login */
 
@@ -315,9 +313,9 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
                   $idx = -$idx - 1;
                   $is_login = TRUE;
               }
-              
+
               log_legal($curtime, $ipv4addr, $user, "STAT:LOGIN", '');
-              
+
               // recovery lost game
               if ($user->stat == "table") {
                   $cookies = new Cookies();
@@ -327,38 +325,36 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
                   $header_out['Location'] = "briskin5/index.php";
                   return TRUE;
               }
-              
-              
+
               // setcookie ("sess", "", time() + 180);      
               $room->standup_update(&$user);
-              
           }
           else {
               /* Login Rendering */
               /* MLANG: "Utente e/o password errati.", "Il nickname deve contenere almeno una lettera o una cifra.", "Spiacenti, non ci sono pi&ugrave; posti liberi. Riprova pi&ugrave; tardi.", "Il tuo nickname &egrave; gi&agrave; in uso." */
               /*
-               if ($idx == -3) 
+               if ($idx == -3)
                $body .= '<div class="urgmsg"><b>'.$mlang_room['userpasserr'][$G_lang].'</b></div>';
                else if ($idx == -2)
                // $body .= '<div class="urgmsg"><b>Il nickname deve contenere almeno una lettera o una cifra.</b></div>';
                $body .= '<div class="urgmsg"><b>'.$mlang_room['userpassmust'][$G_lang].'</b></div>';
-               else if ($idx == -1) 
+               else if ($idx == -1)
                // $body .= '<div class="urgmsg"><b>Spiacenti, non ci sono pi&ugrave; posti liberi. Riprova pi&ugrave; tardi.</b></div>';
                $body .= '<div class="urgmsg"><b>'.$mlang_room['userpassend'][$G_lang].'</b></div>';
                else
                // $body .= '<div class="urgmsg"><b>Il tuo nickname &egrave; gi&agrave; in uso.</b></div>';
                $body .= '<div class="urgmsg"><b>'.$mlang_room['userpassuse'][$G_lang].'</b></div>';
               */
-              
-              if ($idx == -3) 
+
+              if ($idx == -3)
                   $sfx = 'err';
               else if ($idx == -2)
                   $sfx = 'must';
-              else if ($idx == -1) 
+              else if ($idx == -1)
                   $sfx = 'end';
               else
                   $sfx = 'use';
-              
+
               $body .= '<div class="urgmsg"><b>'.$mlang_room['userpass'.$sfx][$G_lang].'</b></div>';
           }
       }
@@ -380,13 +376,13 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
         $i = $ii;
           else
               $i = TABLES_N - $ii - 1;
-          
+
           if ($ii % 4 == 0) {
               $tables .= '<tr id = "tr_noauth'.$ii.'">';
           }
           if (TRUE || !($user->flags & USER_FLAG_ISOLAUTH) || $ii < TABLES_AUTH_N) {
               $tables .= '<td id = "td_noauth'.$ii.'">';
-              
+
               $tables .= '<div class="room_div"><div class="room_tit"><b>'.$mlang_room['tit_tabl'][$G_lang].$i.'</b></div>';
               $tables .= sprintf('<div class="proxhr" id="table%d"></div>', $i);
               $tables .= sprintf('<div class="table_act" id="table_act%d"></div>', $i);
@@ -398,14 +394,13 @@ function index_main(&$room, $transp_type, &$header_out, $addr, $get, $post, $coo
           }
       }
       $tables .= '</table></div>';
-      
-      
+
       $standup .= '<table class="room_standup"><tr><td><div class="room_standup_orig" id="room_standup_orig"></div>';
       $standup .= '<div class="room_ex_standup">';
       /* MLANG: "Giocatori in piedi" */
       // $standup .= '<div id="room_tit"><span class="room_titin"><b>Giocatori in piedi</b> - <a target="_blank" href="weboftrust.php">Come ottenere user e password</a> - </span></div>';
       $standup .= '<div id="room_tit"><span class="room_titin"><b>'.$mlang_room['standing'][$G_lang].'</b></span></div>';
-      
+
       $standup .= sprintf('<div id="standup" class="room_standup"></div>');
       // MLANG Esco.
       $standup .= '<div id="esco" class="esco"><input type="button" class="button" name="xreload"  value="Reload." onclick="act_reloadroom();"><input class="button" name="logout" value="'.$mlang_room['btn_exit'][$G_lang].'" onclick="esco_cb();" type="button"></div>';
@@ -1071,7 +1066,7 @@ else {
 
 ?>
      sess = "<?php echo "$sess"; ?>";
-xstm = new xynt_streaming(window, "<?php echo "$transp_type"; ?>", null /* console */, gst, 'index_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);});
+xstm = new xynt_streaming(window, "<?php echo "$transp_type"; ?>", 80, 2, console, gst, 'index_php', 'sess', sess, $('sandbox'), 'index_rd_ifra.php', function(com){eval(com);});
      xstm.hbit_set(heartbit);
      tra = new train($('room_tit'));
      window.onunload = onunload_cb;
@@ -1132,7 +1127,7 @@ if ($is_login) {
    }
 
    printf("</td><td>");
-?> 
+?>
 <!--  =========== tables ===========  -->
 <input name="sess" type="hidden" value="<?php echo "$user->sess"; ?>">
 <table class="macro"><tr><td>
index 640c227..a21eb6f 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-   
+
 ?>
 <html>
 <head>
 
      window.onload = function() {
         var host = "ws://dodo.birds.van/brisk/xynt_test01.php?isstream=true&transp=websocket&f_test=1"; // SET THIS TO YOUR SERVER
-     
+
         console.log("QUI");
         try
         {
             socket = new WebSocket(host);
             console.log('WebSocket - status ' + socket.readyState);
-             
+
             socket.onopen = function(msg)
             {
                 if(this.readyState == 1)
                     console.log("We are now connected to websocket server. readyState = " + this.readyState);
                 }
             };
-             
+
             //Message received from websocket server
             socket.onmessage = function(msg)
             {
                 console.log(" [ + ] Received: " + msg.data);
             };
-             
+
             //Connection closed
             socket.onclose = function(msg)
             {
                 console.log("Disconnected - status " + this.readyState);
             };
-             
+
             socket.onerror = function()
             {
                 console.log("Some error");
             }
         }
-         
+
         catch(ex)
         {
             console.log('Some exception : '  + ex);
         }
-         
+
      };
  //-->
 </script>
index 11f4f22..f80e8e8 100644 (file)
@@ -1,5 +1,146 @@
 // old targetpage == page and moved into start method
 
+//
+// CLASS transport_ws
+//
+function transport_ws(doc, xynt_streaming, page)
+{
+    this.ctx_new = "";
+    var self = this;
+
+    this.doc = doc;
+    this.failed = false;
+    this.xynt_streaming = xynt_streaming;
+    try {
+        this.ws = new WebSocket(page);
+        this.ws.onopen = function () {
+            self.xynt_streaming.log("onopen");
+            if (this.readyState == 1) {
+                // connected
+                self.ws_cb("open");
+            }
+        };
+        this.ws.onmessage = function (msg) {
+            self.xynt_streaming.log("onmessage");
+            // new data in msg.data
+            self.ctx_new += msg.data;
+        };
+        this.ws.onclose = function (msg) {
+            self.xynt_streaming.log("onclose");
+            self.ws_cb("close");
+        };
+        this.ws.onerror = function () {
+            // on error
+            self.xynt_streaming.log("onerror");
+            self.ws_cb("error");
+        };
+    }
+    catch (ex) {
+        throw "websocket creation failed";
+    }
+
+    this.stopped = false;
+}
+
+transport_ws.prototype = {
+    doc: null,
+    xynt_streaming: "ready",
+    ws: null,
+    stopped: true,
+    failed: false,
+
+    ctx_old: "",
+    ctx_old_len: 0,
+    ctx_new: "",
+
+    // script_clean: 0,
+
+    destroy: function () { /* public */
+        if (this.ws != null) {
+            this.ws_abort();
+        }
+        delete this.ws;
+    },
+
+    ws_cb: function (from) {
+        var ret;
+
+        if (from == "error") {
+            if (this.xynt_streaming != "ready") {
+                if (this.xynt_streaming.transp_fback > 0) {
+                    this.xynt_streaming.transp_fback--;
+                   this.stopped = true;
+                    this.xynt_streaming.reload();
+                }
+            }
+        }
+        if (this.ws != null && this.ws.readyState > 1) {
+           this.stopped = true;
+        }
+    },
+
+    ws_abort: function() {
+        if (this.ws != null) {
+            this.ws.close();
+        }
+    },
+
+    xstr_is_init: function () { /* public */
+        return (true);
+    },
+
+    /* only after a successfull is_initialized call */
+    xstr_is_ready: function () { /* public */
+        return (this.ws.readyState == 1);
+    },
+
+    xstr_set: function () { /* public */
+        // already set
+    },
+
+    ctx_new_is_set: function () { /* public */
+        return (this.ctx_new != null);
+    },
+
+    ctx_new_curlen_get: function () { /* public */
+        return (this.ctx_new.length);
+    },
+
+    ctx_new_getchar: function(idx) { /* public */
+        return (this.ctx_new[idx]);
+    },
+
+    ctx_old_len_is_set: function () { /* public */
+        return (true);
+    },
+
+    ctx_old_len_get: function () { /* public */
+        return (this.ctx_old_len);
+    },
+
+    ctx_old_len_set: function (len) { /* public */
+        this.ctx_old_len = len;
+    },
+
+    ctx_old_len_add: function (len) { /* public */
+        this.ctx_old_len += len;
+    },
+
+    new_part: function () { /* public */
+        return (this.ctx_new.substr(this.ctx_old_len));
+    },
+
+    scrcls_set: function (step) { /* public */
+        // this.script_clean = step;
+    },
+
+    postproc: function () {
+        if (this.stopped && !this.xstr_is_ready()) {
+            this.xynt_streaming.reload();
+        }
+    }
+}
+
 //
 // CLASS transport_xhr
 //
@@ -232,8 +373,6 @@ transport_htmlfile.prototype = {
     }
 }
 
-
-
 //
 // CLASS transport_iframe
 //
@@ -344,10 +483,12 @@ transport_iframe.prototype = {
     }
 }
 
-function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, sandbox, page, cmdproc)
+function xynt_streaming(win, transp_type, transp_port, transp_fback, console, gst, from, cookiename, sess, sandbox, page, cmdproc)
 {
     this.win = win;
     this.transp_type = transp_type;
+    this.transp_port = transp_port;
+    this.transp_fback = transp_fback;
     this.console = console;
     this.gst = gst;
     this.from = from;
@@ -365,12 +506,13 @@ function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess,
     this.mon_wrntime = this.mon_errtime / 2;
 
     this.mon_update();
-
 }
 
 xynt_streaming.prototype = {
     win:               null,
     transp_type:       null,
+    transp_port:         80,
+    transp_fback:         0,
     transp:            null,
     console:           null,
     gst:               null,
@@ -399,7 +541,7 @@ xynt_streaming.prototype = {
     watchdog_ct:       0,
     watchable:         false,
     restart_n:         0,
-    comm_match:        /_*@BEGIN@(.*?)@END@/g, 
+    comm_match:        /_*@BEGIN@(.*?)@END@/g,
     comm_clean:        /_*@BEGIN@(.*?)@END@/,
     stream:            "",
     the_end:           false,
@@ -442,7 +584,11 @@ xynt_streaming.prototype = {
     },
 
     start: function() { /* public */
-        if (this.the_end) 
+        var transp_type;
+        var page;
+
+        // this.log("start "+this.transp_type+" "+this.transp_fback);
+        if (this.the_end)
             return;
 
         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
@@ -452,26 +598,63 @@ xynt_streaming.prototype = {
 
         // page arrangement
         this.page = url_complete(this.win.location.href, this.page);
-        // stat, subst, this.gst.st
 
-        this.page = url_append_args(this.page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
-        this.log(this.page);
+        if (this.transp_fback > 0) {
+            transp_type = "websocket";
+            transp_port = (this.transp_fback == 2 ? 80 : 8080);
+        }
+        else {
+            transp_type = this.transp_type;
+            transp_port = this.transp_port;
+        }
+
+        if (transp_type == "websocket") {
+            var end_proto, first_slash;
 
-        // transport instantiation
-        if (this.transp_type == "xhr") {
-            this.page = url_append_args(this.page, "transp", "xhr");
-            this.transp = new transport_xhr(this.doc, this, this.page);
+            // change protocol
+            this.log("precha ["+this.page+"]");
+            end_proto = this.page.indexOf("://");
+            first_slash = this.page.substring(end_proto+3).indexOf("/");
+
+            page = "ws://" + this.page.substring(end_proto+3, end_proto+3+first_slash) + ":" + transp_port + this.page.substring(end_proto+3 + first_slash);
+        }
+        else {
+            page = this.page;
         }
-        else if (this.transp_type == "iframe") {
-            this.page = url_append_args(this.page, "transp", "iframe");
-            this.transp = new transport_iframe(this.doc, this, this.page);
+        // stat, subst, this.gst.st
+
+        page = url_append_args(page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
+        // this.log("the page:");
+        // this.log(page);
+
+        try {
+            // transport instantiation
+            if (transp_type == "websocket") {
+                page = url_append_args(page, "transp", "websocket");
+                this.transp = new transport_ws(this.doc, this, page);
+            }
+            else if (transp_type == "xhr") {
+                page = url_append_args(page, "transp", "xhr");
+                this.transp = new transport_xhr(this.doc, this, page);
+            }
+            else if (transp_type == "iframe") {
+                page = url_append_args(page, "transp", "iframe");
+                this.transp = new transport_iframe(this.doc, this, page);
+            }
+            else if (transp_type == "htmlfile") {
+                page = url_append_args(page, "transp", "htmlfile");
+                this.transp = new transport_htmlfile(this.doc, this, page);
+            }
+            else
+                return;
         }
-        else if (this.transp_type == "htmlfile") {
-            this.page = url_append_args(this.page, "transp", "htmlfile");
-            this.transp = new transport_htmlfile(this.doc, this, this.page);
+        catch (err) {
+            if (this.transp_fback > 0) {
+                this.transp_fback--;
+                this.start();
+                return;
+            }
         }
-        else
-            return;
 
         // watchdog setting
         this.watchdog_ct  = 0;
@@ -528,7 +711,7 @@ xynt_streaming.prototype = {
 
         if (this.sandbox != null) {
             // from old: var zug = "POLL sess = "+sess+" stat = "+stat+" subst = "+subst+" step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new+" STOP: "+this.stopped;
-            var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;          
+            var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;
             if (zug != this.sandbox.innerHTML)
                this.sandbox.innerHTML = zug;
         }
@@ -550,7 +733,7 @@ xynt_streaming.prototype = {
                 }
 
                 /*
-                  on IE7 the the window frame scope is cleaned after the href is set, so we wait 
+                  on IE7 the the window frame scope is cleaned after the href is set, so we wait
                   for a well know variable value before assign this object value to it (OO is a passion)
                 */
                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
@@ -571,7 +754,7 @@ xynt_streaming.prototype = {
                 this.keepalive_old = this.keepalive_new;
                 this.keepalives_equal = 0;
             }
-            
+
             if (this.keepalives_equal >= this.keepalives_eq_max) {
                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
                 this.reload();
@@ -584,7 +767,7 @@ xynt_streaming.prototype = {
         // PICK COMMANDS FROM STREAM
         do {
             // alert("do--while begin ["+again+"]");
-           // CHECK: maybe again here isn't needed 
+           // CHECK: maybe again here isn't needed
             again = 0;
             try {
                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
@@ -664,7 +847,7 @@ xynt_streaming.prototype = {
            }
            else if (this.gst.comms.length > 0) {
                var singlecomm;
-                
+
                singlecomm = this.gst.comms.shift();
                // alert("EXE"+gugu);
                // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
index 6673d34..c0aa058 100644 (file)
@@ -8,6 +8,59 @@ $desc = array( "Semplice: da 1 a 9 ogni secondo, poi ricomincia (status sempre v
                "Reload limiter: da 1 a 8 ogni secondo e chiude, 9 setta e chiude subito,<br>il client aspetta 3 secondi, e poi da 10 a N ogni secondo, (status sempre verde).");
 
 
+// trim(mb_convert_case($split[0], MB_CASE_TITLE, 'UTF-8'))
+
+function headers_render($header, $len)
+{
+    $cookies = "";
+
+    if (isset($header['Cookies'])) {
+        $cookies = $header['Cookies']->render();
+        unset($header['Cookies']);
+    }
+    if (isset($header['Location'])) {
+        header(sprintf("HTTP/1.1 302 OK\r\n%sLocation: %s", $cookies, $header['Location']));
+    }
+    else if (isset($header['HTTP-Response'])) {
+        header(sprintf("HTTP/1.1 %s", $header['HTTP-Response']));
+        foreach($header as $key => $value) {
+            if (strtolower($key) == "http-response")
+                continue;
+            header(sprintf("%s: %s", $key, $value));
+        }
+        if ($len >= 0) {
+            header(sprintf("Content-Length: %ld", $len));
+        }
+    }
+    else {
+        header("HTTP/1.1 200 OK\r\n");
+
+        if (!isset($header['Date']))
+            header(sprintf("Date: %s", date(DATE_RFC822)));
+        if (!isset($header['Connection']))
+            header("Connection: close");
+        if (!isset($header['Content-Type']))
+            header("Content-Type: text/html");
+        foreach($header as $key => $value) {
+            header(sprintf("%s: %s", $key, $value));
+        }
+        if ($len >= 0) {
+            header(sprintf("Content-Length: %d", $len));
+        }
+        else {
+            header("Cache-Control: no-cache, must-revalidate");
+            header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+            if (!isset($header['Content-Encoding'])) {
+                header("Content-Encoding: chunked");
+            }
+            header("Transfer-Encoding: chunked");
+        }
+        header($cookies);
+    }
+
+    return (TRUE);
+}
+
 $transs = array( "iframe", "websocket", "xhr", "htmlfile" );
 if (!isset($f_trans))
     $f_trans = $transs[0];
@@ -41,24 +94,23 @@ function xcape($s)
   return (str_replace($from, $to, htmlentities($s,ENT_COMPAT,"UTF-8")));
 }
 
-if ($isstream == "true") {
+if (isset($isstream) && $isstream == "true") {
 
     require_once("Obj/transports.phh");
 
-
     if (isset($transp) && $transp == "websocket") {
-        $transp = new Transport_websocket();
+        $trobj = new Transport_websocket();
     }
     else if (isset($transp) && $transp == "xhr") {
-        $transp = new Transport_xhr();
+        $trobj = new Transport_xhr();
     }
     else if (isset($transp) && $transp == "htmlfile") {
-        $transp = new Transport_htmlfile();
+        $trobj = new Transport_htmlfile();
     }
     else {
-        $transp = new Transport_iframe();
+        $trobj = new Transport_iframe();
     }
-    $header_out = array();
+    $headers_out = array();
 
     $init_string = "";
     for ($i = 0 ; $i < 4096 ; $i++) {
@@ -67,31 +119,65 @@ if ($isstream == "true") {
         else
             $init_string .= chr(mt_rand(65, 90));
     }
-    $header = array();
+    $headers_in = getallheaders();
+    $headers = array();
+    foreach ($headers_in as $header_in => $value) {
+        $headers[mb_convert_case($header_in, MB_CASE_TITLE, 'UTF-8')] = $value;
+    }
+    $fp = fopen("/tmp/xynt.log", "a+");
+    fprintf($fp, "here we are\n");
+    fclose($fp);
+
+    $body = $trobj->init("plain", $headers, $headers_out, $init_string, "", "0");
+
+    if ($body === FALSE) {
+        $fp = fopen("/tmp/xynt.log", "a+");
+        fprintf($fp, "init failed\n");
+        fclose($fp);
+    }
+    else {
+        $fp = fopen("/tmp/xynt.log", "a+");
+        fprintf($fp, "after_init [%s] [%s]\n", $transp, print_r($headers_out, TRUE));
+        fprintf($fp, "body [%s][%d]\n", $body, mb_strlen($body, "ASCII"));
+        fclose($fp);
+    }
 
-    $body = $transp->init("plain", $header, $header_out, $init_string, "", "0");
+    if (isset($transp) && $transp == "websocket") {
+        header_remove('Connection');
+        header_remove('Content-Encoding');
+        header_remove('Content-Type');
+        header_remove('Date');
+        header_remove('Keep-Alive');
+        header_remove('Server');
+        header_remove('Transfer-Encoding');
+        header_remove('Vary');
+        header_remove('X-Powered-By');
 
-    foreach ($header_out as $key => $value) {
-        header(sprintf("%s: %s", $key, $value));
+        headers_render($headers_out, 100);
     }
+    $lnz = 0;
+
     print($body);
+    $lnz += mb_strlen($body, "ASCII");
     mop_flush();
 
     switch ($f_test) {
     case 1:
         // from 1 to 9 into the innerHTML and than close
         for ($i = 1 ; $i < 10 ; $i++) {
-            $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
+            $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
             print($chunk);
             mop_flush();
             sleep(1);
         }
+
         break;
     case 2:
         // from 1 to 9 into the innerHTML and than close
         for ($i = 1 ; $i < 10 ; $i++) {
-            $chunk = $transp->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;"));
+            $chunk = $trobj->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;"));
             print($chunk);
+            $lnz += mb_strlen($chunk, "ASCII");
             mop_flush();
             sleep(1);
         }
@@ -99,7 +185,7 @@ if ($isstream == "true") {
     case 3:
         // from 1 to 9 with 60 secs after 8, the client js api must restart stream after 12 secs
         for ($i = 1 ; $i < 10 ; $i++) {
-            $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
+            $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
             print($chunk);
             mop_flush();
             sleep(1);
@@ -111,10 +197,10 @@ if ($isstream == "true") {
         // from 1 to 9 into the innerHTML and than close
         for ($i = 1 ; $i < 10 ; $i++) {
             if ($i != 5) {
-                $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
+                $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
             }
             else {
-                $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';|sleep(gst,3000);", $i));
+                $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';|sleep(gst,3000);", $i));
             }
             print($chunk);
             mop_flush();
@@ -129,10 +215,10 @@ if ($isstream == "true") {
             case 6:
             case 7:
             case 8:
-                $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%s';", xcape($cont[$i - 6])));
+                $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%s';", xcape($cont[$i - 6])));
                 break;
             default:
-                $chunk = $transp->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
+                $chunk = $trobj->chunk($i, sprintf("\$('container').innerHTML = '%d';", $i));
                 break;
             }
             print($chunk);
@@ -144,7 +230,7 @@ if ($isstream == "true") {
     case 6:
         // from 1 to 9 into the innerHTML and than close
         if ($step == 8) {
-            $chunk = $transp->chunk(1, sprintf("gst.st++; \$('container').innerHTML = gst.st;"));
+            $chunk = $trobj->chunk(1, sprintf("gst.st++; \$('container').innerHTML = gst.st;"));
             print($chunk);
             // without this usleep the delay is doubled in iframe stream because 
             // no transp.xynt_streaming back-set is performed
@@ -153,7 +239,7 @@ if ($isstream == "true") {
         }
         else {
             for ($i = 1 ; $i < 10 ; $i++) {
-                $chunk = $transp->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;"));
+                $chunk = $trobj->chunk($i, sprintf("gst.st++; \$('container').innerHTML = gst.st;"));
                 print($chunk);
                 mop_flush();
                 if ($i < 9)
@@ -162,6 +248,10 @@ if ($isstream == "true") {
         }
         break;
     }
+
+    print($trobj->close());
+    mop_flush();
+
     exit;
 }
 ?>
@@ -182,7 +272,7 @@ if ($isstream == "true") {
      var gst = new globst();
      window.onload = function() {
 
-     xstm = new xynt_streaming(window, "<?php echo "$f_trans";?>", null /* console */, gst, 'xynt_test01_php', 'sess', sess, null, 'xynt_test01.php?isstream=true&f_test=<?php echo "$f_test";?>', function(com){eval(com);});
+         xstm = new xynt_streaming(window, "<?php echo "$f_trans";?>", 80, 0, null /* console */, gst, 'xynt_test01_php', 'sess', sess, null, 'xynt_test01.php?isstream=true&f_test=<?php echo "$f_test";?>', function(com){eval(com);});
      xstm.hbit_set(heartbit);
      xstm.start();
  }