Refactoring
onMessage delivers unMaked payload msg validation moved from Message to MessageValidation Unify return types Context return should be input Remove deprecated Connection
This commit is contained in:
parent
af15a56cb4
commit
5cdd8959dc
@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\RFC6455\Version\RFC6455;
|
|
||||||
use Ratchet\AbstractConnectionDecorator;
|
|
||||||
use Ratchet\RFC6455\Version\DataInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* {@inheritdoc}
|
|
||||||
* @property \StdClass $WebSocket
|
|
||||||
*/
|
|
||||||
class Connection extends AbstractConnectionDecorator {
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function send($msg) {
|
|
||||||
if (!$this->WebSocket->closing) {
|
|
||||||
if (!($msg instanceof DataInterface)) {
|
|
||||||
$msg = new Frame($msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getConnection()->send($msg->getContents());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function close($code = 1000) {
|
|
||||||
if ($this->WebSocket->closing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($code instanceof DataInterface) {
|
|
||||||
$this->send($code);
|
|
||||||
} else {
|
|
||||||
$this->send(new Frame(pack('n', $code), true, Frame::OP_CLOSE));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getConnection()->close();
|
|
||||||
|
|
||||||
$this->WebSocket->closing = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,9 +7,6 @@ class Message implements \IteratorAggregate, MessageInterface {
|
|||||||
*/
|
*/
|
||||||
private $_frames;
|
private $_frames;
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
private $binary = false;
|
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->_frames = new \SplDoublyLinkedList;
|
$this->_frames = new \SplDoublyLinkedList;
|
||||||
}
|
}
|
||||||
@ -56,30 +53,9 @@ class Message implements \IteratorAggregate, MessageInterface {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
* @todo Also, I should perhaps check the type...control frames (ping/pong/close) are not to be considered part of a message
|
|
||||||
*/
|
*/
|
||||||
public function addFrame(FrameInterface $fragment) {
|
public function addFrame(FrameInterface $fragment) {
|
||||||
// should the validation stuff be somewhere else?
|
|
||||||
// it really needs the context of the message to know whether there is a problem
|
|
||||||
if ($this->_frames->isEmpty()) {
|
|
||||||
$this->binary = $fragment->getOpcode() == Frame::OP_BINARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if this is a continuation frame when there is no
|
|
||||||
// frames yet added
|
|
||||||
if ($this->_frames->count() == 0 && $fragment->getOpcode() == Frame::OP_CONTINUE) {
|
|
||||||
return Frame::CLOSE_PROTOCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if this is not a continuation frame when there is already frames
|
|
||||||
if ($this->_frames->count() > 0 && $fragment->getOpcode() != Frame::OP_CONTINUE) {
|
|
||||||
return Frame::CLOSE_PROTOCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_frames->push($fragment);
|
$this->_frames->push($fragment);
|
||||||
|
|
||||||
return true;
|
|
||||||
//return $this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,8 +123,11 @@ class Message implements \IteratorAggregate, MessageInterface {
|
|||||||
/**
|
/**
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isBinary()
|
public function isBinary() {
|
||||||
{
|
if ($this->_frames->isEmpty()) {
|
||||||
return $this->binary;
|
throw new \UnderflowException('Not enough data has been received to determine if message is binary');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Frame::OP_BINARY === $this->_frames->bottom()->getOpcode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@ use Ratchet\RFC6455\Messaging\Protocol\MessageInterface;
|
|||||||
use Ratchet\RFC6455\Messaging\Protocol\FrameInterface;
|
use Ratchet\RFC6455\Messaging\Protocol\FrameInterface;
|
||||||
|
|
||||||
interface ContextInterface {
|
interface ContextInterface {
|
||||||
|
/**
|
||||||
|
* @param FrameInterface $frame
|
||||||
|
* @return FrameInterface
|
||||||
|
*/
|
||||||
public function setFrame(FrameInterface $frame = null);
|
public function setFrame(FrameInterface $frame = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,6 +15,10 @@ interface ContextInterface {
|
|||||||
*/
|
*/
|
||||||
public function getFrame();
|
public function getFrame();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MessageInterface $message
|
||||||
|
* @return MessageInterface
|
||||||
|
*/
|
||||||
public function setMessage(MessageInterface $message = null);
|
public function setMessage(MessageInterface $message = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,9 @@ use Ratchet\RFC6455\Messaging\Protocol\Message;
|
|||||||
use Ratchet\RFC6455\Messaging\Validation\MessageValidator;
|
use Ratchet\RFC6455\Messaging\Validation\MessageValidator;
|
||||||
|
|
||||||
class MessageStreamer {
|
class MessageStreamer {
|
||||||
/** @var MessageValidator */
|
/**
|
||||||
|
* @var MessageValidator
|
||||||
|
*/
|
||||||
private $validator;
|
private $validator;
|
||||||
|
|
||||||
function __construct(ValidatorInterface $encodingValidator, $expectMask = false) {
|
function __construct(ValidatorInterface $encodingValidator, $expectMask = false) {
|
||||||
@ -17,27 +19,27 @@ class MessageStreamer {
|
|||||||
public function onData($data, ContextInterface $context) {
|
public function onData($data, ContextInterface $context) {
|
||||||
$overflow = '';
|
$overflow = '';
|
||||||
|
|
||||||
$context->getMessage() || $context->setMessage($this->newMessage());
|
$message = $context->getMessage() ?: $context->setMessage($this->newMessage());
|
||||||
$context->getFrame() || $context->setFrame($this->newFrame());
|
$frame = $context->getFrame() ?: $context->setFrame($this->newFrame());
|
||||||
|
|
||||||
$frame = $context->getFrame();
|
|
||||||
|
|
||||||
$frame->addBuffer($data);
|
$frame->addBuffer($data);
|
||||||
if ($frame->isCoalesced()) {
|
if ($frame->isCoalesced()) {
|
||||||
$validFrame = $this->validator->validateFrame($frame);
|
$frameCount = $message->count();
|
||||||
if (true !== $validFrame) {
|
$prevFrame = $frameCount > 0 ? $message[$frameCount - 1] : null;
|
||||||
$context->onClose($validFrame);
|
|
||||||
|
|
||||||
return;
|
$frameStatus = $this->validator->validateFrame($frame, $prevFrame);
|
||||||
|
|
||||||
|
if (0 !== $frameStatus) {
|
||||||
|
return $context->onClose($frameStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
$opcode = $frame->getOpcode();
|
$opcode = $frame->getOpcode();
|
||||||
if ($opcode > 2) {
|
if ($opcode > 2) {
|
||||||
switch ($opcode) {
|
switch ($opcode) {
|
||||||
case $frame::OP_PING:
|
case Frame::OP_PING:
|
||||||
$context->onPing($frame);
|
$context->onPing($frame);
|
||||||
break;
|
break;
|
||||||
case $frame::OP_PONG:
|
case Frame::OP_PONG:
|
||||||
$context->onPong($frame);
|
$context->onPong($frame);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -54,20 +56,18 @@ class MessageStreamer {
|
|||||||
|
|
||||||
$overflow = $frame->extractOverflow();
|
$overflow = $frame->extractOverflow();
|
||||||
|
|
||||||
$frameAdded = $context->getMessage()->addFrame($frame);
|
$frame->unMaskPayload();
|
||||||
if (true !== $frameAdded) {
|
$message->addFrame($frame);
|
||||||
$context->onClose($frameAdded);
|
|
||||||
}
|
|
||||||
$context->setFrame(null);
|
$context->setFrame(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($context->getMessage()->isCoalesced()) {
|
if ($message->isCoalesced()) {
|
||||||
$msgCheck = $this->validator->checkMessage($context->getMessage());
|
$msgCheck = $this->validator->checkMessage($message);
|
||||||
if ($msgCheck !== true) {
|
if (true !== $msgCheck) {
|
||||||
$context->onClose($msgCheck);
|
return $context->onClose($msgCheck);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
$context->onMessage($context->getMessage());
|
|
||||||
|
$context->onMessage($message);
|
||||||
$context->setMessage(null);
|
$context->setMessage(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,31 +18,11 @@ class MessageValidator {
|
|||||||
/**
|
/**
|
||||||
* Determine if a message is valid
|
* Determine if a message is valid
|
||||||
* @param \Ratchet\RFC6455\Messaging\Protocol\MessageInterface
|
* @param \Ratchet\RFC6455\Messaging\Protocol\MessageInterface
|
||||||
* @return bool|int true if valid - false if incomplete - int of recomended close code
|
* @return bool|int true if valid - false if incomplete - int of recommended close code
|
||||||
*/
|
*/
|
||||||
public function checkMessage(MessageInterface $message) {
|
public function checkMessage(MessageInterface $message) {
|
||||||
// Need a progressive and complete check...this is only satisfying complete
|
|
||||||
if (!$message->isCoalesced()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$frame = $message[0];
|
$frame = $message[0];
|
||||||
|
|
||||||
$frameCheck = $this->validateFrame($frame);
|
|
||||||
if (true !== $frameCheck) {
|
|
||||||
return $frameCheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This seems incorrect - how could a frame exist with message count being 0?
|
|
||||||
if ($frame::OP_CONTINUE === $frame->getOpcode() && 0 === count($message)) {
|
|
||||||
return $frame::CLOSE_PROTOCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// I (mbonneau) don't understand this - seems to always kill the tests
|
|
||||||
// if (count($message) > 0 && $frame::OP_CONTINUE !== $frame->getOpcode()) {
|
|
||||||
// return $frame::CLOSE_PROTOCOL;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!$message->isBinary()) {
|
if (!$message->isBinary()) {
|
||||||
$parsed = $message->getPayload();
|
$parsed = $message->getPayload();
|
||||||
if (!$this->validator->checkEncoding($parsed, 'UTF-8')) {
|
if (!$this->validator->checkEncoding($parsed, 'UTF-8')) {
|
||||||
@ -54,41 +34,42 @@ class MessageValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Frame $frame
|
* @param FrameInterface $frame
|
||||||
* @return bool|int Return true if everything is good, an integer close code if not
|
* @param FrameInterface $previousFrame
|
||||||
|
* @return int Return 0 if everything is good, an integer close code if not
|
||||||
*/
|
*/
|
||||||
public function validateFrame(Frame $frame) {
|
public function validateFrame(FrameInterface $frame, FrameInterface $previousFrame = null) {
|
||||||
if (false !== $frame->getRsv1() ||
|
if (false !== $frame->getRsv1() ||
|
||||||
false !== $frame->getRsv2() ||
|
false !== $frame->getRsv2() ||
|
||||||
false !== $frame->getRsv3()
|
false !== $frame->getRsv3()
|
||||||
) {
|
) {
|
||||||
return $frame::CLOSE_PROTOCOL;
|
return Frame::CLOSE_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be checking all frames
|
// Should be checking all frames
|
||||||
if ($this->checkForMask && !$frame->isMasked()) {
|
if ($this->checkForMask && !$frame->isMasked()) {
|
||||||
return $frame::CLOSE_PROTOCOL;
|
return Frame::CLOSE_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
$opcode = $frame->getOpcode();
|
$opcode = $frame->getOpcode();
|
||||||
|
|
||||||
if ($opcode > 2) {
|
if ($opcode > 2) {
|
||||||
if ($frame->getPayloadLength() > 125 || !$frame->isFinal()) {
|
if ($frame->getPayloadLength() > 125 || !$frame->isFinal()) {
|
||||||
return $frame::CLOSE_PROTOCOL;
|
return Frame::CLOSE_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($opcode) {
|
switch ($opcode) {
|
||||||
case $frame::OP_CLOSE:
|
case Frame::OP_CLOSE:
|
||||||
$closeCode = 0;
|
$closeCode = 0;
|
||||||
|
|
||||||
$bin = $frame->getPayload();
|
$bin = $frame->getPayload();
|
||||||
|
|
||||||
if (empty($bin)) {
|
if (empty($bin)) {
|
||||||
return $frame::CLOSE_NORMAL;
|
return Frame::CLOSE_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($bin) == 1) {
|
if (strlen($bin) == 1) {
|
||||||
return $frame::CLOSE_PROTOCOL;
|
return Frame::CLOSE_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($bin) >= 2) {
|
if (strlen($bin) >= 2) {
|
||||||
@ -96,24 +77,34 @@ class MessageValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$frame->isValidCloseCode($closeCode)) {
|
if (!$frame->isValidCloseCode($closeCode)) {
|
||||||
return $frame::CLOSE_PROTOCOL;
|
return Frame::CLOSE_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->validator->checkEncoding(substr($bin, 2), 'UTF-8')) {
|
if (!$this->validator->checkEncoding(substr($bin, 2), 'UTF-8')) {
|
||||||
return $frame::CLOSE_BAD_PAYLOAD;
|
return Frame::CLOSE_BAD_PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $frame::CLOSE_NORMAL;
|
return Frame::CLOSE_NORMAL;
|
||||||
break;
|
break;
|
||||||
case $frame::OP_PING:
|
case Frame::OP_PING:
|
||||||
case $frame::OP_PONG:
|
case Frame::OP_PONG:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return $frame::CLOSE_PROTOCOL;
|
return Frame::CLOSE_PROTOCOL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (Frame::OP_CONTINUE === $frame->getOpcode() && null === $previousFrame) {
|
||||||
|
return Frame::CLOSE_PROTOCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $previousFrame && Frame::OP_CONTINUE != $frame->getOpcode()) {
|
||||||
|
return Frame::CLOSE_PROTOCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ class ConnectionContext implements Ratchet\RFC6455\Messaging\Streaming\ContextIn
|
|||||||
|
|
||||||
public function setFrame(\Ratchet\RFC6455\Messaging\Protocol\FrameInterface $frame = null) {
|
public function setFrame(\Ratchet\RFC6455\Messaging\Protocol\FrameInterface $frame = null) {
|
||||||
$this->_frame = $frame;
|
$this->_frame = $frame;
|
||||||
|
|
||||||
|
return $frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFrame() {
|
public function getFrame() {
|
||||||
@ -26,6 +28,8 @@ class ConnectionContext implements Ratchet\RFC6455\Messaging\Streaming\ContextIn
|
|||||||
|
|
||||||
public function setMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $message = null) {
|
public function setMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $message = null) {
|
||||||
$this->_message = $message;
|
$this->_message = $message;
|
||||||
|
|
||||||
|
return $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMessage() {
|
public function getMessage() {
|
||||||
@ -33,10 +37,6 @@ class ConnectionContext implements Ratchet\RFC6455\Messaging\Streaming\ContextIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) {
|
public function onMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) {
|
||||||
foreach ($msg as $frame) {
|
|
||||||
$frame->unMaskPayload();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_conn->write($msg->getContents());
|
$this->_conn->write($msg->getContents());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user