Merge branch 'master' into ws
authorMatteo Nastasi (mop) <nastasi@alternativeoutput.it>
Fri, 16 Aug 2013 08:55:18 +0000 (10:55 +0200)
committerMatteo Nastasi (mop) <nastasi@alternativeoutput.it>
Fri, 16 Aug 2013 08:55:57 +0000 (10:55 +0200)
TODO.txt
web/Obj/brisk.phh
web/Obj/transports.phh
web/Obj/user.phh
web/briskin5/Obj/briskin5.phh
web/ws.php [new file with mode: 0644]
web/xynt_test01.php

index abc81bf..404a808 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -3,6 +3,13 @@
 
   FEATURES |
  ----------+
+   - WEBSOCKET TRANSPORT
+     . client (xynt_streaming.js)
+     . server (transport.phh)
+
+     M1: xynt_test01.php working
+
+     . manage headers correctly in sac-a-push
 
    - improved S
      . db update (add components, maybe single string)
index 593b6e2..707b20a 100644 (file)
@@ -2366,7 +2366,7 @@ class Room
               }
 
               $content = "";
-              $user->stream_init($s_a_p->rndstr, $enc, $header_out, $content, $get, $post, $cookie);
+              $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 a77fad7..3b6e79c 100644 (file)
@@ -58,7 +58,8 @@ class Transport_template {
     function Transport_template() {
     }
 
-    function init($enc, &$header_out, $init_string, $base, $step)
+    // return string value is appended to the content of the returned page
+    function init($enc, $header, &$header_out, $init_string, $base, $step)
     {
     }
 
@@ -75,12 +76,120 @@ class Transport_template {
     }
 }
 
+class Transport_websocket {
+    $magicGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+    function Transport_websocket() {
+    }
+
+    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]);
+            }
+        }
+        if (isset($headers['get'])) {
+            $user->requestedResource = $headers['get'];
+        } else {
+            // todo: fail the connection
+            $handshakeResponse = "HTTP/1.1 405 Method Not Allowed\r\n\r\n";                    
+        }
+        if (!isset($headers['host']) || !$this->checkHost($headers['host'])) {
+            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+        }
+        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";
+        }
+        if (!isset($headers['sec-websocket-key'])) {
+            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+        } else {
+            
+        }
+        if (!isset($headers['sec-websocket-version']) || strtolower($headers['sec-websocket-version']) != 13) {
+            $handshakeResponse = "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13";
+        }
+        if (($this->headerOriginRequired && !isset($headers['origin']) ) || ($this->headerOriginRequired && !$this->checkOrigin($headers['origin']))) {
+            $handshakeResponse = "HTTP/1.1 403 Forbidden";
+        }
+        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->headerSecWebSocketExtensionsRequired && !isset($headers['sec-websocket-extensions'])) || ($this->headerSecWebSocketExtensionsRequired && !$this->checkWebsocExtensions($header['sec-websocket-extensions']))) {
+            $handshakeResponse = "HTTP/1.1 400 Bad Request";
+        }
+        
+        // Done verifying the _required_ headers and optionally required headers.
+        
+        if (isset($handshakeResponse)) {
+            socket_write($user->socket,$handshakeResponse,strlen($handshakeResponse));
+            $this->disconnect($user->socket);
+            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)));
+        }
+        $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);
+    }
+    
+
+    function init($enc, $header, &$header_out, $init_string, $base, $step)
+    {
+        
+
+
+
+        $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"';
+
+        return ($ret);
+    }
+
+    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 ("");
+    }
+
+    function chunk($step, $cont)
+    {
+        return ("@BEGIN@".$cont."@END@");
+    }
+}
+
 class Transport_xhr {
 
     function Transport_xhr() {
     }
 
-    function init($enc, &$header_out, $init_string, $base, $step)
+    function init($enc, $header, &$header_out, $init_string, $base, $step)
     {
         $ret = sprintf("@BEGIN@ /* %s */ @END@", $init_string);
         if ($enc != 'plain')
@@ -114,7 +223,7 @@ class Transport_iframe {
     function Transport_iframe() {
     }
 
-    function init($enc, &$header_out, $init_string, $base, $step)
+    function init($enc, $header, &$header_out, $init_string, $base, $step)
     {
         $ret = "";
 
index f52bc3e..55a3a75 100644 (file)
@@ -699,7 +699,7 @@ class User {
    stat
    step
 */
-function stream_init($init_string, $enc, &$header_out, &$body, $get, $post, $cookie)
+function stream_init($init_string, $enc, $header, &$header_out, &$body, $get, $post, $cookie)
 {
     $curtime = time();
     
@@ -720,7 +720,7 @@ function stream_init($init_string, $enc, &$header_out, &$body, $get, $post, $coo
     
     $this->rd_data_set($curtime, $transp, $enc, $stat, $subst, $step, $from);
     
-    $body .= $this->rd_transp->init($enc, &$header_out, $init_string, self::base_get(), $this->rd_scristp);
+    $body .= $this->rd_transp->init($enc, $header, &$header_out, $init_string, self::base_get(), $this->rd_scristp);
 
     return TRUE;
   }
index 6e3a52f..f45b210 100644 (file)
@@ -1233,7 +1233,8 @@ class Bin5 {
                 }
                 
                 $content = "";
-                $user->stream_init($s_a_p->rndstr, $enc, $header_out, $content, $get, $post, $cookie);
+                $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");
                 
diff --git a/web/ws.php b/web/ws.php
new file mode 100644 (file)
index 0000000..640c227
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+   
+?>
+<html>
+<head>
+<title>WS</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="xynt-streaming.js"></script>
+<script type="text/javascript" src="commons.js"></script>
+<script type="text/javascript" src="heartbit.js"></script>
+
+<!-- <script type="text/javascript" src="myconsole.js"></script> -->
+
+<script type="text/javascript"><!--
+     var socket;
+
+     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>
+</head>
+<body>
\ No newline at end of file
index f9efb7b..6673d34 100644 (file)
@@ -8,7 +8,7 @@ $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).");
 
 
-$transs = array( "iframe", "xhr", "htmlfile" );
+$transs = array( "iframe", "websocket", "xhr", "htmlfile" );
 if (!isset($f_trans))
     $f_trans = $transs[0];
 
@@ -46,7 +46,10 @@ if ($isstream == "true") {
     require_once("Obj/transports.phh");
 
 
-    if (isset($transp) && $transp == "xhr") {
+    if (isset($transp) && $transp == "websocket") {
+        $transp = new Transport_websocket();
+    }
+    else if (isset($transp) && $transp == "xhr") {
         $transp = new Transport_xhr();
     }
     else if (isset($transp) && $transp == "htmlfile") {
@@ -64,8 +67,9 @@ if ($isstream == "true") {
         else
             $init_string .= chr(mt_rand(65, 90));
     }
+    $header = array();
 
-    $body = $transp->init("plain", $header_out, $init_string, "", "0");
+    $body = $transp->init("plain", $header, $header_out, $init_string, "", "0");
 
     foreach ($header_out as $key => $value) {
         header(sprintf("%s: %s", $key, $value));