Esempio n. 1
0
 /**
  * Returns bytes from the buffer based on the current length or current search byte.
  *
  * @return string
  */
 private function remove() : string
 {
     if (null !== $this->byte && false !== ($position = $this->buffer->search($this->byte))) {
         if (0 === $this->length || $position < $this->length) {
             return $this->buffer->shift($position + 1);
         }
         return $this->buffer->shift($this->length);
     }
     if (0 === $this->length) {
         return $this->buffer->drain();
     }
     return $this->buffer->shift($this->length);
 }
Esempio n. 2
0
 /**
  * @coroutine
  *
  * Reads a single line from the stream.
  *
  * Reads from the stream until a newline is reached or the stream is closed.
  * The newline characters are included in the returned string. If reading ends
  * in the middle of a character, the trailing bytes are not consumed.
  *
  * @param float|int $timeout Number of seconds until the returned promise is rejected with a TimeoutException
  *     if no data is received. Use 0 for no timeout.
  *
  * @return \Generator
  *
  * @resolve string A line of text read from the stream.
  *
  * @throws \Icicle\Awaitable\Exception\TimeoutException If the operation times out.
  * @throws \Icicle\Stream\Exception\UnreadableException If the stream is no longer readable.
  * @throws \Icicle\Stream\Exception\ClosedException If the stream is unexpectedly closed.
  */
 public function readLine(float $timeout = 0) : \Generator
 {
     $newLineSize = strlen($this->newLine);
     // Check if a new line is already in the buffer.
     if (($pos = $this->buffer->search($this->newLine)) !== false) {
         return $this->buffer->shift($pos + $newLineSize);
     }
     $this->buffer->push(yield from Stream\readUntil($this->stream, $this->newLine, 0, $timeout));
     if (($pos = $this->buffer->search($this->newLine)) !== false) {
         return $this->buffer->shift($pos + $newLineSize);
     }
     return $this->buffer->shift(strlen(mb_strcut((string) $this->buffer, 0, null, $this->encoding)));
 }
Esempio n. 3
0
 /**
  * {@inheritdoc}
  *
  * @throws \Icicle\Http\Exception\MessageException If an invalid chunk length is found.
  */
 protected function send(string $data, float $timeout = 0, bool $end = false) : \Generator
 {
     $this->buffer->push($data);
     $data = '';
     while (!$this->buffer->isEmpty()) {
         if (0 === $this->length) {
             // Read chunk length.
             if (false === ($position = $this->buffer->search("\r\n"))) {
                 return yield from parent::send($data, $timeout, $end);
             }
             $length = rtrim($this->buffer->remove($position + 2), "\r\n");
             if ($position = strpos($length, ';')) {
                 $length = substr($length, 0, $position);
             }
             if (!preg_match('/^[a-f0-9]+$/i', $length)) {
                 yield from parent::send('', $timeout, true);
                 throw new MessageException(Response::BAD_REQUEST, 'Invalid chunk length.');
             }
             $this->length = hexdec($length) + 2;
             if (2 === $this->length) {
                 // Termination chunk.
                 $end = true;
             }
         }
         if (2 < $this->length) {
             // Read chunk.
             $buffer = $this->buffer->remove($this->length - 2);
             $this->length -= strlen($buffer);
             $data .= $buffer;
         }
         if (2 >= $this->length) {
             // Remove \r\n after chunk.
             $this->length -= strlen($this->buffer->remove($this->length));
         }
     }
     return yield from parent::send($data, $timeout, $end);
 }
Esempio n. 4
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));
 }