Create MessageStreamer, move some things
This commit is contained in:
parent
d0202c8c71
commit
8653b92115
@ -1,15 +1,9 @@
|
||||
<?php
|
||||
namespace Ratchet\RFC6455\Handshake;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
// TODO remove all these
|
||||
use Ratchet\ConnectionInterface;
|
||||
use Ratchet\MessageInterface;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Ratchet\RFC6455\Encoding\ValidatorInterface;
|
||||
use Ratchet\RFC6455\Message\Message;
|
||||
use Ratchet\RFC6455\Message\Frame;
|
||||
use Ratchet\RFC6455\Message\Connection;
|
||||
|
||||
/**
|
||||
* The latest version of the WebSocket protocol
|
||||
@ -31,7 +25,7 @@ class Negotiator implements NegotiatorInterface {
|
||||
* @var array
|
||||
* @deprecated
|
||||
*/
|
||||
private $closeCodes = array();
|
||||
private $closeCodes = [];
|
||||
|
||||
public function __construct(ValidatorInterface $validator) {
|
||||
$this->verifier = new RequestVerifier;
|
||||
@ -44,7 +38,7 @@ class Negotiator implements NegotiatorInterface {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isProtocol(RequestInterface $request) {
|
||||
public function isProtocol(ServerRequestInterface $request) {
|
||||
$version = (int)(string)$request->getHeader('Sec-WebSocket-Version');
|
||||
|
||||
return ($this->getVersionNumber() === $version);
|
||||
@ -60,34 +54,16 @@ class Negotiator implements NegotiatorInterface {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handshake(RequestInterface $request) {
|
||||
public function handshake(ServerRequestInterface $request) {
|
||||
if (true !== $this->verifier->verifyAll($request)) {
|
||||
return new Response(400);
|
||||
}
|
||||
|
||||
return new Response(101, array(
|
||||
return new Response(101, [
|
||||
'Upgrade' => 'websocket'
|
||||
, 'Connection' => 'Upgrade'
|
||||
, 'Sec-WebSocket-Accept' => $this->sign((string)$request->getHeader('Sec-WebSocket-Key'))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param \Ratchet\ConnectionInterface $conn
|
||||
* @param \Ratchet\MessageInterface $coalescedCallback
|
||||
* @return \Ratchet\WebSocket\Version\RFC6455\Connection
|
||||
*/
|
||||
public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) {
|
||||
$upgraded = new Connection($conn);
|
||||
|
||||
if (!isset($upgraded->WebSocket)) {
|
||||
$upgraded->WebSocket = new \StdClass;
|
||||
}
|
||||
|
||||
$upgraded->WebSocket->coalescedCallback = $coalescedCallback;
|
||||
|
||||
return $upgraded;
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,102 +72,7 @@ class Negotiator implements NegotiatorInterface {
|
||||
* @param string $data
|
||||
*/
|
||||
public function onMessage(ConnectionInterface $from, $data) {
|
||||
$overflow = '';
|
||||
|
||||
if (!isset($from->WebSocket->message)) {
|
||||
$from->WebSocket->message = $this->newMessage();
|
||||
}
|
||||
|
||||
// There is a frame fragment attached to the connection, add to it
|
||||
if (!isset($from->WebSocket->frame)) {
|
||||
$from->WebSocket->frame = $this->newFrame();
|
||||
}
|
||||
|
||||
$from->WebSocket->frame->addBuffer($data);
|
||||
if ($from->WebSocket->frame->isCoalesced()) {
|
||||
$frame = $from->WebSocket->frame;
|
||||
|
||||
if ($opcode > 2) {
|
||||
switch ($opcode) {
|
||||
case $frame::OP_CLOSE:
|
||||
$closeCode = 0;
|
||||
|
||||
$bin = $frame->getPayload();
|
||||
|
||||
if (empty($bin)) {
|
||||
return $from->close();
|
||||
}
|
||||
|
||||
if (strlen($bin) >= 2) {
|
||||
list($closeCode) = array_merge(unpack('n*', substr($bin, 0, 2)));
|
||||
}
|
||||
|
||||
if (!$this->isValidCloseCode($closeCode)) {
|
||||
return $from->close($frame::CLOSE_PROTOCOL);
|
||||
}
|
||||
|
||||
if (!$this->validator->checkEncoding(substr($bin, 2), 'UTF-8')) {
|
||||
return $from->close($frame::CLOSE_BAD_PAYLOAD);
|
||||
}
|
||||
|
||||
return $from->close($frame);
|
||||
break;
|
||||
case $frame::OP_PING:
|
||||
$from->send($this->newFrame($frame->getPayload(), true, $frame::OP_PONG));
|
||||
break;
|
||||
case $frame::OP_PONG:
|
||||
break;
|
||||
default:
|
||||
return $from->close($frame::CLOSE_PROTOCOL);
|
||||
break;
|
||||
}
|
||||
|
||||
$overflow = $from->WebSocket->frame->extractOverflow();
|
||||
|
||||
unset($from->WebSocket->frame, $frame, $opcode);
|
||||
|
||||
if (strlen($overflow) > 0) {
|
||||
$this->onMessage($from, $overflow);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$overflow = $from->WebSocket->frame->extractOverflow();
|
||||
|
||||
$from->WebSocket->message->addFrame($from->WebSocket->frame);
|
||||
unset($from->WebSocket->frame);
|
||||
}
|
||||
|
||||
if ($from->WebSocket->message->isCoalesced()) {
|
||||
$parsed = $from->WebSocket->message->getPayload();
|
||||
unset($from->WebSocket->message);
|
||||
|
||||
$from->WebSocket->coalescedCallback->onMessage($from, $parsed);
|
||||
}
|
||||
|
||||
if (strlen($overflow) > 0) {
|
||||
$this->onMessage($from, $overflow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @return RFC6455\Message
|
||||
*/
|
||||
public function newMessage() {
|
||||
return new Message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param string|null $payload
|
||||
* @param bool|null $final
|
||||
* @param int|null $opcode
|
||||
* @return RFC6455\Frame
|
||||
*/
|
||||
public function newFrame($payload = null, $final = null, $opcode = null) {
|
||||
return new Frame($payload, $final, $opcode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,41 +84,4 @@ class Negotiator implements NegotiatorInterface {
|
||||
public function sign($key) {
|
||||
return base64_encode(sha1($key . static::GUID, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Determine if a close code is valid
|
||||
* @param int|string
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidCloseCode($val) {
|
||||
if (array_key_exists($val, $this->closeCodes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($val >= 3000 && $val <= 4999) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Creates a private lookup of valid, private close codes
|
||||
*/
|
||||
protected function setCloseCodes() {
|
||||
$this->closeCodes[Frame::CLOSE_NORMAL] = true;
|
||||
$this->closeCodes[Frame::CLOSE_GOING_AWAY] = true;
|
||||
$this->closeCodes[Frame::CLOSE_PROTOCOL] = true;
|
||||
$this->closeCodes[Frame::CLOSE_BAD_DATA] = true;
|
||||
//$this->closeCodes[Frame::CLOSE_NO_STATUS] = true;
|
||||
//$this->closeCodes[Frame::CLOSE_ABNORMAL] = true;
|
||||
$this->closeCodes[Frame::CLOSE_BAD_PAYLOAD] = true;
|
||||
$this->closeCodes[Frame::CLOSE_POLICY] = true;
|
||||
$this->closeCodes[Frame::CLOSE_TOO_BIG] = true;
|
||||
$this->closeCodes[Frame::CLOSE_MAND_EXT] = true;
|
||||
$this->closeCodes[Frame::CLOSE_SRV_ERR] = true;
|
||||
//$this->closeCodes[Frame::CLOSE_TLS] = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
namespace Ratchet\RFC6455\Handshake;
|
||||
use Ratchet\MessageInterface;
|
||||
use Ratchet\ConnectionInterface;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* A standard interface for interacting with the various version of the WebSocket protocol
|
||||
@ -13,10 +13,10 @@ interface NegotiatorInterface {
|
||||
|
||||
/**
|
||||
* Given an HTTP header, determine if this version should handle the protocol
|
||||
* @param \Guzzle\Http\Message\RequestInterface $request
|
||||
* @param ServerRequestInterface $request
|
||||
* @return bool
|
||||
*/
|
||||
function isProtocol(RequestInterface $request);
|
||||
function isProtocol(ServerRequestInterface $request);
|
||||
|
||||
/**
|
||||
* Although the version has a name associated with it the integer returned is the proper identification
|
||||
@ -26,10 +26,10 @@ interface NegotiatorInterface {
|
||||
|
||||
/**
|
||||
* Perform the handshake and return the response headers
|
||||
* @param \Guzzle\Http\Message\RequestInterface $request
|
||||
* @return \Guzzle\Http\Message\Response
|
||||
* @param ServerRequestInterface $request
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
function handshake(RequestInterface $request);
|
||||
function handshake(ServerRequestInterface $request);
|
||||
|
||||
/**
|
||||
* Add supported protocols. If the request has any matching the response will include one
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
namespace Ratchet\RFC6455\Handshake;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* These are checks to ensure the client requested handshake are valid
|
||||
@ -12,7 +11,7 @@ class RequestVerifier {
|
||||
|
||||
/**
|
||||
* Given an array of the headers this method will run through all verification methods
|
||||
* @param \Guzzle\Http\Message\RequestInterface $request
|
||||
* @param RequestInterface $request
|
||||
* @return bool TRUE if all headers are valid, FALSE if 1 or more were invalid
|
||||
*/
|
||||
public function verifyAll(RequestInterface $request) {
|
||||
|
162
src/Messaging/Streaming/MessageStreamer.php
Normal file
162
src/Messaging/Streaming/MessageStreamer.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Ratchet\RFC6455\Messaging\Streaming;
|
||||
|
||||
use Evenement\EventEmitterInterface;
|
||||
use Evenement\EventEmitterTrait;
|
||||
use Ratchet\RFC6455\Messaging\Protocol\Frame;
|
||||
use Ratchet\RFC6455\Messaging\Protocol\Message;
|
||||
|
||||
class MessageStreamer implements EventEmitterInterface {
|
||||
use EventEmitterTrait;
|
||||
|
||||
/** @var Frame */
|
||||
private $currentFrame;
|
||||
|
||||
/** @var Message */
|
||||
private $currentMessage;
|
||||
|
||||
/** @var array */
|
||||
private $closeCodes = [];
|
||||
|
||||
public function onData($data) {
|
||||
$overflow = '';
|
||||
|
||||
if (!isset($this->currentMessage)) {
|
||||
$this->currentMessage = $this->newMessage();
|
||||
}
|
||||
|
||||
// There is a frame fragment attached to the connection, add to it
|
||||
if (!isset($this->currentFrame)) {
|
||||
$this->currentFrame = $this->newFrame();
|
||||
}
|
||||
|
||||
$frame = $this->currentFrame;
|
||||
|
||||
$frame->addBuffer($data);
|
||||
if ($frame->isCoalesced()) {
|
||||
$opcode = $frame->getOpcode();
|
||||
if ($opcode > 2) {
|
||||
switch ($opcode) {
|
||||
case $frame::OP_CLOSE:
|
||||
$closeCode = 0;
|
||||
|
||||
$bin = $frame->getPayload();
|
||||
|
||||
if (empty($bin)) {
|
||||
$this->emit('close', [null]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen($bin) >= 2) {
|
||||
list($closeCode) = array_merge(unpack('n*', substr($bin, 0, 2)));
|
||||
}
|
||||
|
||||
if (!$this->isValidCloseCode($closeCode)) {
|
||||
$this->emit('close', [$frame::CLOSE_PROTOCOL]);
|
||||
return;
|
||||
}
|
||||
|
||||
// todo:
|
||||
//if (!$this->validator->checkEncoding(substr($bin, 2), 'UTF-8')) {
|
||||
// $this->emit('close', [$frame::CLOSE_BAD_PAYLOAD]);
|
||||
// return;
|
||||
//}
|
||||
|
||||
$this->emit('close', [$closeCode]);
|
||||
return;
|
||||
break;
|
||||
case $frame::OP_PING:
|
||||
// this should probably be automatic
|
||||
//$from->send($this->newFrame($frame->getPayload(), true, $frame::OP_PONG));
|
||||
$this->emit('ping', [$frame]);
|
||||
break;
|
||||
case $frame::OP_PONG:
|
||||
$this->emit('pong', [$frame]);
|
||||
break;
|
||||
default:
|
||||
$this->emit('close', [$frame::CLOSE_PROTOCOL]);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
$overflow = $frame->extractOverflow();
|
||||
|
||||
unset($this->currentFrame, $frame, $opcode);
|
||||
|
||||
if (strlen($overflow) > 0) {
|
||||
$this->onData($overflow);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$overflow = $frame->extractOverflow();
|
||||
|
||||
$this->currentMessage->addFrame($this->currentFrame);
|
||||
unset($this->currentFrame);
|
||||
}
|
||||
|
||||
if ($this->currentMessage->isCoalesced()) {
|
||||
$this->emit('message', [$this->currentMessage]);
|
||||
//$parsed = $from->WebSocket->message->getPayload();
|
||||
unset($this->currentMessage);
|
||||
}
|
||||
|
||||
if (strlen($overflow) > 0) {
|
||||
$this->onData($overflow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Message
|
||||
*/
|
||||
public function newMessage() {
|
||||
return new Message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $payload
|
||||
* @param bool|null $final
|
||||
* @param int|null $opcode
|
||||
* @return Frame
|
||||
*/
|
||||
public function newFrame($payload = null, $final = null, $opcode = null) {
|
||||
return new Frame($payload, $final, $opcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a close code is valid
|
||||
* @param int|string
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidCloseCode($val) {
|
||||
if (array_key_exists($val, $this->closeCodes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($val >= 3000 && $val <= 4999) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a private lookup of valid, private close codes
|
||||
*/
|
||||
protected function setCloseCodes() {
|
||||
$this->closeCodes[Frame::CLOSE_NORMAL] = true;
|
||||
$this->closeCodes[Frame::CLOSE_GOING_AWAY] = true;
|
||||
$this->closeCodes[Frame::CLOSE_PROTOCOL] = true;
|
||||
$this->closeCodes[Frame::CLOSE_BAD_DATA] = true;
|
||||
//$this->closeCodes[Frame::CLOSE_NO_STATUS] = true;
|
||||
//$this->closeCodes[Frame::CLOSE_ABNORMAL] = true;
|
||||
$this->closeCodes[Frame::CLOSE_BAD_PAYLOAD] = true;
|
||||
$this->closeCodes[Frame::CLOSE_POLICY] = true;
|
||||
$this->closeCodes[Frame::CLOSE_TOO_BIG] = true;
|
||||
$this->closeCodes[Frame::CLOSE_MAND_EXT] = true;
|
||||
$this->closeCodes[Frame::CLOSE_SRV_ERR] = true;
|
||||
//$this->closeCodes[Frame::CLOSE_TLS] = true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user