Kaynağa Gözat

support permessage-deflate

walkor 1 yıl önce
ebeveyn
işleme
0857164d33
1 değiştirilmiş dosya ile 80 ekleme ve 4 silme
  1. 80 4
      src/Protocols/Websocket.php

+ 80 - 4
src/Protocols/Websocket.php

@@ -51,6 +51,13 @@ class Websocket
     public const BINARY_TYPE_BLOB = "\x81";
 
     /**
+     * Websocket blob type.
+     *
+     * @var string
+     */
+    const BINARY_TYPE_BLOB_DEFLATE = "\xc1";
+
+    /**
      * Websocket arraybuffer type.
      *
      * @var string
@@ -58,6 +65,13 @@ class Websocket
     public const BINARY_TYPE_ARRAYBUFFER = "\x82";
 
     /**
+     * Websocket arraybuffer type.
+     *
+     * @var string
+     */
+    const BINARY_TYPE_ARRAYBUFFER_DEFLATE = "\xc2";
+
+    /**
      * Check the integrity of the package.
      *
      * @param string $buffer
@@ -250,12 +264,16 @@ class Websocket
             throw new Exception("You can't send(" . gettype($buffer) . ") to client, you need to convert it to string. ");
         }
 
-        $len = strlen($buffer);
         if (empty($connection->websocketType)) {
             $connection->websocketType = static::BINARY_TYPE_BLOB;
         }
 
+        if (\ord($connection->websocketType) & 64) {
+            $buffer = static::deflate($connection, $buffer);
+        }
+
         $firstByte = $connection->websocketType;
+        $len = strlen($buffer);
 
         if ($len <= 125) {
             $encodeBuffer = $firstByte . chr($len) . $buffer;
@@ -308,8 +326,11 @@ class Websocket
      */
     public static function decode(string $buffer, TcpConnection $connection): string
     {
-        $firstByte = ord($buffer[1]);
-        $len = $firstByte & 127;
+        $firstByte = ord($buffer[0]);
+        $secondByte = ord($buffer[1]);
+        $len = $secondByte & 127;
+        $isFinFrame = (bool)($firstByte >> 7);
+        $rsv1 = 64 === ($firstByte & 64);
 
         if ($len === 126) {
             $masks = substr($buffer, 4, 4);
@@ -328,17 +349,72 @@ class Websocket
         $decoded = $data ^ $masks;
         if ($connection->context->websocketCurrentFrameLength) {
             $connection->context->websocketDataBuffer .= $decoded;
+            if ($rsv1) {
+                return static::inflate($connection, $connection->context->websocketDataBuffer, $isFinFrame);
+            }
             return $connection->context->websocketDataBuffer;
         }
-
         if ($connection->context->websocketDataBuffer !== '') {
             $decoded = $connection->context->websocketDataBuffer . $decoded;
             $connection->context->websocketDataBuffer = '';
         }
+        if ($rsv1) {
+            return static::inflate($connection, $decoded, $isFinFrame);
+        }
         return $decoded;
     }
 
     /**
+     * Inflate.
+     *
+     * @param TcpConnection $connection
+     * @param string $buffer
+     * @param bool $isFinFrame
+     * @return false|string
+     */
+    protected static function inflate(TcpConnection $connection, string $buffer, bool $isFinFrame)
+    {
+        if (!isset($connection->context->inflator)) {
+            $connection->context->inflator = \inflate_init(
+                \ZLIB_ENCODING_RAW,
+                [
+                    'level'    => -1,
+                    'memory'   => 8,
+                    'window'   => 15,
+                    'strategy' => \ZLIB_DEFAULT_STRATEGY
+                ]
+            );
+        }
+        if ($isFinFrame) {
+            $buffer .= "\x00\x00\xff\xff";
+        }
+        return \inflate_add($connection->context->inflator, $buffer);
+    }
+
+    /**
+     * Deflate.
+     *
+     * @param TcpConnection $connection
+     * @param string $buffer
+     * @return false|string
+     */
+    protected static function deflate(TcpConnection $connection, string $buffer)
+    {
+        if (!isset($connection->context->deflator)) {
+            $connection->context->deflator = \deflate_init(
+                \ZLIB_ENCODING_RAW,
+                [
+                    'level'    => -1,
+                    'memory'   => 8,
+                    'window'   => 15,
+                    'strategy' => \ZLIB_DEFAULT_STRATEGY
+                ]
+            );
+        }
+        return \substr(\deflate_add($connection->context->deflator, $buffer), 0, -4);
+    }
+
+    /**
      * Websocket handshake.
      *
      * @param string $buffer