From 1f608f1d3a2e2af716e8f0d4928dd48e7f800897 Mon Sep 17 00:00:00 2001
From: Chris Boden <cboden@gmail.com>
Date: Wed, 30 Nov 2011 10:08:11 -0500
Subject: [PATCH] Stubs for RFC protocol version

---
 .../Application/WebSocket/Version/HyBi10.php  | 129 +---------------
 .../Application/WebSocket/Version/RFC6455.php | 146 ++++++++++++++++++
 .../Version/{HyBi10 => RFC6455}/Frame.php     |   2 +-
 .../Version/{HyBi10 => RFC6455}/Message.php   |   2 +-
 .../WebSocket/Version/HyBi10Test.php          |   2 +-
 .../Version/{HyBi10 => RFC6455}/FrameTest.php |   6 +-
 6 files changed, 157 insertions(+), 130 deletions(-)
 create mode 100644 lib/Ratchet/Application/WebSocket/Version/RFC6455.php
 rename lib/Ratchet/Application/WebSocket/Version/{HyBi10 => RFC6455}/Frame.php (99%)
 rename lib/Ratchet/Application/WebSocket/Version/{HyBi10 => RFC6455}/Message.php (96%)
 rename tests/Ratchet/Tests/Application/WebSocket/Version/{HyBi10 => RFC6455}/FrameTest.php (97%)

diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php
index 78efb88..5d90b66 100644
--- a/lib/Ratchet/Application/WebSocket/Version/HyBi10.php
+++ b/lib/Ratchet/Application/WebSocket/Version/HyBi10.php
@@ -1,21 +1,10 @@
 <?php
 namespace Ratchet\Application\WebSocket\Version;
-use Ratchet\Application\WebSocket\Util\HTTP;
 
-/**
- * The HyBi-10 version, identified in the headers as version 8, is currently implemented by the latest Chrome and Firefix version
- * @link http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
- * @todo Naming...I'm not fond of this naming convention...
- */
-class HyBi10 implements VersionInterface {
-    const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
-
-    /**
-     * @todo When I support later version (that implement extension) change >= 6 to 6 through 10 (or w/e #)
-     */
+class HyBi10 extends RFC6455 {
     public static function isProtocol(array $headers) {
         if (isset($headers['Sec-Websocket-Version'])) {
-            if ((int)$headers['Sec-Websocket-Version'] >= 6) {
+            if ((int)$headers['Sec-Websocket-Version'] >= 6 && (int)$headers['Sec-Websocket-Version'] < 13) {
                 return true;
             }
         }
@@ -23,126 +12,18 @@ class HyBi10 implements VersionInterface {
         return false;
     }
 
-    /**
-     * @return array
-     * I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string
-     */
-    public function handshake($message) {
-        $headers = HTTP::getHeaders($message);
-        $key     = $this->sign($headers['Sec-Websocket-Key']);
-
-        return array(
-            ''                     => 'HTTP/1.1 101 Switching Protocols'
-          , 'Upgrade'              => 'websocket'
-          , 'Connection'           => 'Upgrade'
-          , 'Sec-WebSocket-Accept' => $this->sign($headers['Sec-Websocket-Key'])
-//          , 'Sec-WebSocket-Protocol' => ''
-        );
-   }
-
     /**
      * @return HyBi10\Message
-     */
+     * /
     public function newMessage() {
         return new HyBi10\Message;
     }
 
     /**
      * @return HyBi10\Frame
-     */
+     * /
     public function newFrame() {
         return new HyBi10\Frame;
     }
-
-    /**
-     * Thanks to @lemmingzshadow for the code on decoding a HyBi-10 frame
-     * @link https://github.com/lemmingzshadow/php-websocket
-     * @todo look into what happens when false is returned here
-     * @param string
-     * @return string
-     */
-    public function frame($message, $mask = true) {
-        $payload = $message;
-        $type    = 'text';
-        $masked  = $mask;
-
-        $frameHead = array();
-        $frame = '';
-        $payloadLength = strlen($payload);
-
-        switch($type) {
-            case 'text':
-                // first byte indicates FIN, Text-Frame (10000001):
-                $frameHead[0] = 129;                
-            break;            
-
-            case 'close':
-                // first byte indicates FIN, Close Frame(10001000):
-                $frameHead[0] = 136;
-            break;
-
-            case 'ping':
-                // first byte indicates FIN, Ping frame (10001001):
-                $frameHead[0] = 137;
-            break;
-
-            case 'pong':
-                // first byte indicates FIN, Pong frame (10001010):
-                $frameHead[0] = 138;
-            break;
-        }
-
-        // set mask and payload length (using 1, 3 or 9 bytes) 
-        if($payloadLength > 65535) {
-            $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);
-            $frameHead[1] = ($masked === true) ? 255 : 127;
-            for($i = 0; $i < 8; $i++) {
-                $frameHead[$i+2] = bindec($payloadLengthBin[$i]);
-            }
-            // most significant bit MUST be 0 (return false if to much data)
-            if($frameHead[2] > 127) {
-                return false;
-            }
-        } elseif($payloadLength > 125) {
-            $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);
-            $frameHead[1] = ($masked === true) ? 254 : 126;
-            $frameHead[2] = bindec($payloadLengthBin[0]);
-            $frameHead[3] = bindec($payloadLengthBin[1]);
-        } else {
-            $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;
-        }
-
-        // convert frame-head to string:
-        foreach(array_keys($frameHead) as $i) {
-            $frameHead[$i] = chr($frameHead[$i]);
-        } if($masked === true) {
-            // generate a random mask:
-            $mask = array();
-            for($i = 0; $i < 4; $i++)
-            {
-                $mask[$i] = chr(rand(0, 255));
-            }
-
-            $frameHead = array_merge($frameHead, $mask);            
-        }                        
-        $frame = implode('', $frameHead);
-
-        // append payload to frame:
-        $framePayload = array();
-        for($i = 0; $i < $payloadLength; $i++) {        
-            $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
-        }
-
-        return $frame;
-    }
-
-    /**
-     * Used when doing the handshake to encode the key, verifying client/server are speaking the same language
-     * @param string
-     * @return string
-     * @internal
-     */
-    public function sign($key) {
-        return base64_encode(sha1($key . static::GUID, 1));
-    }
+    /**/
 }
\ No newline at end of file
diff --git a/lib/Ratchet/Application/WebSocket/Version/RFC6455.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php
new file mode 100644
index 0000000..a95d5bd
--- /dev/null
+++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455.php
@@ -0,0 +1,146 @@
+<?php
+namespace Ratchet\Application\WebSocket\Version;
+use Ratchet\Application\WebSocket\Util\HTTP;
+
+/**
+ * @link http://www.rfc-editor.org/authors/rfc6455.txt
+ */
+class RFC6455 implements VersionInterface {
+    const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
+
+    /**
+     * @todo When I support later version (that implement extension) change >= 6 to 6 through 10 (or w/e #)
+     */
+    public static function isProtocol(array $headers) {
+        if (isset($headers['Sec-Websocket-Version'])) {
+            if ((int)$headers['Sec-Websocket-Version'] == 13) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @return array
+     * I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string
+     */
+    public function handshake($message) {
+        $headers = HTTP::getHeaders($message);
+        $key     = $this->sign($headers['Sec-Websocket-Key']);
+
+        return array(
+            ''                     => 'HTTP/1.1 101 Switching Protocols'
+          , 'Upgrade'              => 'websocket'
+          , 'Connection'           => 'Upgrade'
+          , 'Sec-WebSocket-Accept' => $this->sign($headers['Sec-Websocket-Key'])
+//          , 'Sec-WebSocket-Protocol' => ''
+        );
+   }
+
+    /**
+     * @return RFC6455\Message
+     */
+    public function newMessage() {
+        return new RFC6455\Message;
+    }
+
+    /**
+     * @return RFC6455\Frame
+     */
+    public function newFrame() {
+        return new RFC6455\Frame;
+    }
+
+    /**
+     * Thanks to @lemmingzshadow for the code on decoding a HyBi-10 frame
+     * @link https://github.com/lemmingzshadow/php-websocket
+     * @todo look into what happens when false is returned here
+     * @param string
+     * @return string
+     */
+    public function frame($message, $mask = true) {
+        $payload = $message;
+        $type    = 'text';
+        $masked  = $mask;
+
+        $frameHead = array();
+        $frame = '';
+        $payloadLength = strlen($payload);
+
+        switch($type) {
+            case 'text':
+                // first byte indicates FIN, Text-Frame (10000001):
+                $frameHead[0] = 129;                
+            break;            
+
+            case 'close':
+                // first byte indicates FIN, Close Frame(10001000):
+                $frameHead[0] = 136;
+            break;
+
+            case 'ping':
+                // first byte indicates FIN, Ping frame (10001001):
+                $frameHead[0] = 137;
+            break;
+
+            case 'pong':
+                // first byte indicates FIN, Pong frame (10001010):
+                $frameHead[0] = 138;
+            break;
+        }
+
+        // set mask and payload length (using 1, 3 or 9 bytes) 
+        if($payloadLength > 65535) {
+            $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);
+            $frameHead[1] = ($masked === true) ? 255 : 127;
+            for($i = 0; $i < 8; $i++) {
+                $frameHead[$i+2] = bindec($payloadLengthBin[$i]);
+            }
+            // most significant bit MUST be 0 (return false if to much data)
+            if($frameHead[2] > 127) {
+                return false;
+            }
+        } elseif($payloadLength > 125) {
+            $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);
+            $frameHead[1] = ($masked === true) ? 254 : 126;
+            $frameHead[2] = bindec($payloadLengthBin[0]);
+            $frameHead[3] = bindec($payloadLengthBin[1]);
+        } else {
+            $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;
+        }
+
+        // convert frame-head to string:
+        foreach(array_keys($frameHead) as $i) {
+            $frameHead[$i] = chr($frameHead[$i]);
+        } if($masked === true) {
+            // generate a random mask:
+            $mask = array();
+            for($i = 0; $i < 4; $i++)
+            {
+                $mask[$i] = chr(rand(0, 255));
+            }
+
+            $frameHead = array_merge($frameHead, $mask);            
+        }                        
+        $frame = implode('', $frameHead);
+
+        // append payload to frame:
+        $framePayload = array();
+        for($i = 0; $i < $payloadLength; $i++) {        
+            $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
+        }
+
+        return $frame;
+    }
+
+    /**
+     * Used when doing the handshake to encode the key, verifying client/server are speaking the same language
+     * @param string
+     * @return string
+     * @internal
+     */
+    public function sign($key) {
+        return base64_encode(sha1($key . static::GUID, 1));
+    }
+}
\ No newline at end of file
diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10/Frame.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455/Frame.php
similarity index 99%
rename from lib/Ratchet/Application/WebSocket/Version/HyBi10/Frame.php
rename to lib/Ratchet/Application/WebSocket/Version/RFC6455/Frame.php
index 0ee94a5..22efca2 100644
--- a/lib/Ratchet/Application/WebSocket/Version/HyBi10/Frame.php
+++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455/Frame.php
@@ -1,5 +1,5 @@
 <?php
-namespace Ratchet\Application\WebSocket\Version\HyBi10;
+namespace Ratchet\Application\WebSocket\Version\RFC6455;
 use Ratchet\Application\WebSocket\Version\FrameInterface;
 
 class Frame implements FrameInterface {
diff --git a/lib/Ratchet/Application/WebSocket/Version/HyBi10/Message.php b/lib/Ratchet/Application/WebSocket/Version/RFC6455/Message.php
similarity index 96%
rename from lib/Ratchet/Application/WebSocket/Version/HyBi10/Message.php
rename to lib/Ratchet/Application/WebSocket/Version/RFC6455/Message.php
index add834c..1b255d8 100644
--- a/lib/Ratchet/Application/WebSocket/Version/HyBi10/Message.php
+++ b/lib/Ratchet/Application/WebSocket/Version/RFC6455/Message.php
@@ -1,5 +1,5 @@
 <?php
-namespace Ratchet\Application\WebSocket\Version\HyBi10;
+namespace Ratchet\Application\WebSocket\Version\RFC6455;
 use Ratchet\Application\WebSocket\Version\MessageInterface;
 use Ratchet\Application\WebSocket\Version\FrameInterface;
 
diff --git a/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10Test.php b/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10Test.php
index 6585da3..9b22b09 100644
--- a/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10Test.php
+++ b/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10Test.php
@@ -1,7 +1,7 @@
 <?php
 namespace Ratchet\Tests\Application\WebSocket\Version;
 use Ratchet\Application\WebSocket\Version\HyBi10;
-use Ratchet\Application\WebSocket\Version\HyBi10\Frame;
+use Ratchet\Application\WebSocket\Version\RFC6455\Frame;
 
 /**
  * @covers Ratchet\Application\WebSocket\Version\Hybi10
diff --git a/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10/FrameTest.php b/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php
similarity index 97%
rename from tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10/FrameTest.php
rename to tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php
index 0dbd13b..b9582f8 100644
--- a/tests/Ratchet/Tests/Application/WebSocket/Version/HyBi10/FrameTest.php
+++ b/tests/Ratchet/Tests/Application/WebSocket/Version/RFC6455/FrameTest.php
@@ -1,9 +1,9 @@
 <?php
-namespace Ratchet\Tests\Application\WebSocket\Version\HyBi10;
-use Ratchet\Application\WebSocket\Version\HyBi10\Frame;
+namespace Ratchet\Tests\Application\WebSocket\Version\RFC6455;
+use Ratchet\Application\WebSocket\Version\RFC6455\Frame;
 
 /**
- * @covers Ratchet\Application\WebSocket\Version\HyBi10\Frame
+ * @covers Ratchet\Application\WebSocket\Version\RFC6455\Frame
  * @todo getMaskingKey, getPayloadStartingByte don't have tests yet
  * @todo Could use some clean up in general, I had to rush to fix a bug for a deadline, sorry.
  */