Пример #1
0
 /**
  * @coroutine
  *
  * @param int $maxSize Max frame size.
  * @param float|int $timeout
  *
  * @return \Generator
  *
  * @resolve \Icicle\WebSocket\Protocol\Rfc6455Frame
  *
  * @throws \Icicle\WebSocket\Exception\FrameException
  */
 public function read(int $maxSize, float $timeout = 0) : \Generator
 {
     $buffer = new Buffer();
     try {
         do {
             $buffer->push(yield from $this->socket->read(0, null, $timeout));
         } while ($buffer->getLength() < 2);
         $bytes = unpack('Cflags/Clength', $buffer->shift(2));
         $rsv = $bytes['flags'] & self::RSV_MASK;
         $opcode = $bytes['flags'] & self::OPCODE_MASK;
         $final = (bool) ($bytes['flags'] & self::FIN_MASK);
         $masked = (bool) ($bytes['length'] & self::MASK_FLAG_MASK);
         $size = $bytes['length'] & self::LENGTH_MASK;
         if ($masked === $this->masked) {
             throw new FrameException(sprintf('Received %s frame.', $masked ? 'masked' : 'unmasked'));
         }
         if ($size === self::TWO_BYTE_LENGTH_FLAG) {
             while ($buffer->getLength() < 2) {
                 $buffer->push(yield from $this->socket->read(0, null, $timeout));
             }
             $bytes = unpack('nlength', $buffer->shift(2));
             $size = $bytes['length'];
             if ($size < self::TWO_BYTE_LENGTH_FLAG) {
                 throw new FrameException('Frame format error.');
             }
         } elseif ($size === self::EIGHT_BYTE_LENGTH_FLAG) {
             while ($buffer->getLength() < 8) {
                 $buffer->push(yield from $this->socket->read(0, null, $timeout));
             }
             $bytes = unpack('Nhigh/Nlow', $buffer->shift(8));
             $size = $bytes['high'] << 32 | $bytes['low'];
             if ($size < self::TWO_BYTE_MAX_LENGTH) {
                 throw new FrameException('Frame format error.');
             }
         }
         if ($size > $maxSize) {
             throw new PolicyException('Frame size exceeded max allowed size.');
         }
         if ($masked) {
             while ($buffer->getLength() < self::MASK_LENGTH) {
                 $buffer->push(yield from $this->socket->read(0, null, $timeout));
             }
             $mask = $buffer->shift(self::MASK_LENGTH);
         }
         while ($buffer->getLength() < $size) {
             $buffer->push(yield from $this->socket->read(0, null, $timeout));
         }
         $data = $buffer->shift($size);
         if ($masked) {
             $data ^= str_repeat($mask, (int) (($size + self::MASK_LENGTH - 1) / self::MASK_LENGTH));
         }
     } finally {
         if (!$buffer->isEmpty()) {
             $this->socket->unshift((string) $buffer);
         }
     }
     return new Frame($opcode, $data, $rsv, $final);
 }
Пример #2
0
 /**
  * @param \Icicle\Stream\Structures\Buffer $buffer
  * @param \Icicle\Socket\Socket $socket
  * @param float|int $timeout
  *
  * @return \Generator
  *
  * @throws \Icicle\Http\Exception\MessageException
  * @throws \Icicle\Http\Exception\ParseException
  */
 protected function readHeaders(Buffer $buffer, Socket $socket, float $timeout = 0) : \Generator
 {
     $size = 0;
     $headers = [];
     do {
         while (false === ($position = $buffer->search("\r\n"))) {
             if ($buffer->getLength() >= $this->maxSize) {
                 throw new MessageException(Response::REQUEST_HEADER_TOO_LARGE, sprintf('Message header exceeded maximum size of %d bytes.', $this->maxSize));
             }
             $buffer->push(yield from $socket->read(0, null, $timeout));
         }
         $length = $position + 2;
         $line = $buffer->shift($length);
         if (2 === $length) {
             return $headers;
         }
         $size += $length;
         $parts = explode(':', $line, 2);
         if (2 !== count($parts)) {
             throw new ParseException('Found header without colon.');
         }
         list($name, $value) = $parts;
         $name = Message\decode($name);
         $value = Message\decode(trim($value));
         // No check for case as Message class will automatically combine similarly named headers.
         if (!isset($headers[$name])) {
             $headers[$name] = [$value];
         } else {
             $headers[$name][] = $value;
         }
     } while ($size < $this->maxSize);
     throw new MessageException(Response::REQUEST_HEADER_TOO_LARGE, sprintf('Message header exceeded maximum size of %d bytes.', $this->maxSize));
 }