[WebSocket] Hixie refactoring
Created parent interface for messages and frames Created Hixie Connection Applied updated interfaces to Hixie versions Removed __toString on msgs/frames since there could be 2-3 types returned
This commit is contained in:
parent
439ac1234f
commit
49d68ba7df
28
src/Ratchet/WebSocket/Version/DataInterface.php
Normal file
28
src/Ratchet/WebSocket/Version/DataInterface.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\WebSocket\Version;
|
||||||
|
|
||||||
|
interface DataInterface {
|
||||||
|
/**
|
||||||
|
* Determine if the message is complete or still fragmented
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function isCoalesced();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes the payload is set to be
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function getPayloadLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the payload (message) sent from peer
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPayload();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw contents of the message
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getContents();
|
||||||
|
}
|
@ -1,29 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
|
|
||||||
interface FrameInterface {
|
interface FrameInterface extends DataInterface {
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function isCoalesced();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Add incoming data to the frame from peer
|
||||||
* @param string
|
* @param string
|
||||||
* @todo Theoretically, there won't be a buffer overflow (end of frame + start of new frame) - but test later, return a string with overflow here
|
|
||||||
*/
|
*/
|
||||||
function addBuffer($buf);
|
function addBuffer($buf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* Is this the final frame in a fragmented message?
|
||||||
*/
|
|
||||||
// function isFragment();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function isFinal();
|
function isFinal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Was the payload masked?
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function isMasked();
|
function isMasked();
|
||||||
@ -36,21 +28,11 @@ interface FrameInterface {
|
|||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
function getPayloadLength();
|
//function getReceivedPayloadLength();
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
// function getReceivedPayloadLength();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 32-big string
|
* 32-big string
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function getMaskingKey();
|
function getMaskingKey();
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string
|
|
||||||
*/
|
|
||||||
function getPayload();
|
|
||||||
}
|
}
|
@ -1,7 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
|
use Ratchet\MessageInterface;
|
||||||
|
use Ratchet\WebSocket\Version\Hixie76\Connection;
|
||||||
use Guzzle\Http\Message\RequestInterface;
|
use Guzzle\Http\Message\RequestInterface;
|
||||||
use Guzzle\Http\Message\Response;
|
use Guzzle\Http\Message\Response;
|
||||||
|
use Ratchet\WebSocket\Version\Hixie76\Frame;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FOR THE LOVE OF BEER, PLEASE PLEASE PLEASE DON'T allow the use of this in your application!
|
* FOR THE LOVE OF BEER, PLEASE PLEASE PLEASE DON'T allow the use of this in your application!
|
||||||
@ -22,6 +26,9 @@ class Hixie76 implements VersionInterface {
|
|||||||
return !(null === $request->getHeader('Sec-WebSocket-Key2', true));
|
return !(null === $request->getHeader('Sec-WebSocket-Key2', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
public function getVersionNumber() {
|
public function getVersionNumber() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -46,25 +53,47 @@ class Hixie76 implements VersionInterface {
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Hixie76\Message
|
|
||||||
*/
|
|
||||||
public function newMessage() {
|
|
||||||
return new Hixie76\Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Hixie76\Frame
|
|
||||||
*/
|
|
||||||
public function newFrame() {
|
|
||||||
return new Hixie76\Frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function frame($message, $mask = true) {
|
public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) {
|
||||||
return chr(0) . $message . chr(255);
|
$upgraded = new Connection($conn);
|
||||||
|
|
||||||
|
if (!isset($upgraded->WebSocket)) {
|
||||||
|
$upgraded->WebSocket = new \StdClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
$upgraded->WebSocket->coalescedCallback = $coalescedCallback;
|
||||||
|
|
||||||
|
return $upgraded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onMessage(ConnectionInterface $from, $data) {
|
||||||
|
$overflow = '';
|
||||||
|
|
||||||
|
if (!isset($from->WebSocket->frame)) {
|
||||||
|
$from->WebSocket->frame = $this->newFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
$from->WebSocket->frame->addBuffer($data);
|
||||||
|
if ($from->WebSocket->frame->isCoalesced()) {
|
||||||
|
$overflow = $from->WebSocket->frame->extractOverflow();
|
||||||
|
|
||||||
|
$parsed = $from->WebSocket->frame->getPayload();
|
||||||
|
unset($from->WebSocket->frame);
|
||||||
|
|
||||||
|
$from->WebSocket->coalescedCallback->onMessage($from, $parsed);
|
||||||
|
|
||||||
|
unset($from->WebSocket->frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($overflow) > 0) {
|
||||||
|
$this->onMessage($from, $overflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newFrame() {
|
||||||
|
return new Frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateKeyNumber($key) {
|
public function generateKeyNumber($key) {
|
||||||
|
16
src/Ratchet/WebSocket/Version/Hixie76/Connection.php
Normal file
16
src/Ratchet/WebSocket/Version/Hixie76/Connection.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\WebSocket\Version\Hixie76;
|
||||||
|
use Ratchet\AbstractConnectionDecorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
class Connection extends AbstractConnectionDecorator {
|
||||||
|
public function send($msg) {
|
||||||
|
return $this->getConnection()->send(chr(0) . $msg . chr(255));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close() {
|
||||||
|
return $this->getConnection()->close();
|
||||||
|
}
|
||||||
|
}
|
@ -75,4 +75,12 @@ class Frame implements FrameInterface {
|
|||||||
|
|
||||||
return substr($this->_data, 1, strlen($this->_data) - 2);
|
return substr($this->_data, 1, strlen($this->_data) - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getContents() {
|
||||||
|
return $this->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extractOverflow() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,68 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\WebSocket\Version\Hixie76;
|
|
||||||
use Ratchet\WebSocket\Version\MessageInterface;
|
|
||||||
use Ratchet\WebSocket\Version\FrameInterface;
|
|
||||||
|
|
||||||
class Message implements MessageInterface {
|
|
||||||
/**
|
|
||||||
* @var Ratchet\WebSocket\Version\FrameInterface
|
|
||||||
*/
|
|
||||||
protected $_frame = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function __toString() {
|
|
||||||
return $this->getPayload();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function isCoalesced() {
|
|
||||||
if (!($this->_frame instanceof FrameInterface)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_frame->isCoalesced();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function addFrame(FrameInterface $fragment) {
|
|
||||||
if (null !== $this->_frame) {
|
|
||||||
throw new \OverflowException('Hixie76 does not support multiple framing of messages');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_frame = $fragment;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getOpcode() {
|
|
||||||
// Hixie76 only supported text messages
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getPayloadLength() {
|
|
||||||
throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getPayload() {
|
|
||||||
if (!$this->isCoalesced()) {
|
|
||||||
throw new \UnderflowException('Message has not been fully buffered yet');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_frame->getPayload();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
|
|
||||||
/**
|
interface MessageInterface extends DataInterface {
|
||||||
* @todo Consider making parent interface/composite for Message/Frame with (isCoalesced, getOpcdoe, getPayloadLength, getPayload)
|
|
||||||
*/
|
|
||||||
interface MessageInterface {
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function isCoalesced();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param FragmentInterface
|
* @param FragmentInterface
|
||||||
* @return MessageInterface
|
* @return MessageInterface
|
||||||
@ -20,14 +12,4 @@ interface MessageInterface {
|
|||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
function getOpcode();
|
function getOpcode();
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
function getPayloadLength();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function getPayload();
|
|
||||||
}
|
}
|
@ -2,14 +2,14 @@
|
|||||||
namespace Ratchet\WebSocket\Version\RFC6455;
|
namespace Ratchet\WebSocket\Version\RFC6455;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
use Ratchet\AbstractConnectionDecorator;
|
use Ratchet\AbstractConnectionDecorator;
|
||||||
use Ratchet\WebSocket\Version\FrameInterface;
|
use Ratchet\WebSocket\Version\DataInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
class Connection extends AbstractConnectionDecorator {
|
class Connection extends AbstractConnectionDecorator {
|
||||||
public function send($msg) {
|
public function send($msg) {
|
||||||
if (!($msg instanceof FrameInterface)) {
|
if (!($msg instanceof DataInterface)) {
|
||||||
$msg = new Frame($msg);
|
$msg = new Frame($msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,6 @@ class Message implements MessageInterface {
|
|||||||
$this->_frames = new \SplDoublyLinkedList;
|
$this->_frames = new \SplDoublyLinkedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function __toString() {
|
|
||||||
return $this->getPayload();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -87,4 +80,21 @@ class Message implements MessageInterface {
|
|||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getContents() {
|
||||||
|
if (!$this->isCoalesced()) {
|
||||||
|
throw new \UnderflowException("Message has not been put back together yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
$buffer = '';
|
||||||
|
|
||||||
|
foreach ($this->_frames as $frame) {
|
||||||
|
$buffer .= $frame->getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\WebSocket\Version;
|
namespace Ratchet\WebSocket\Version;
|
||||||
use Ratchet\MessageInterface;
|
use Ratchet\MessageInterface;
|
||||||
|
use Ratchet\ConnectionInterface;
|
||||||
use Guzzle\Http\Message\RequestInterface;
|
use Guzzle\Http\Message\RequestInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,20 +26,26 @@ interface VersionInterface extends MessageInterface {
|
|||||||
* Perform the handshake and return the response headers
|
* Perform the handshake and return the response headers
|
||||||
* @param Guzzle\Http\Message\RequestInterface
|
* @param Guzzle\Http\Message\RequestInterface
|
||||||
* @return Guzzle\Http\Message\Response
|
* @return Guzzle\Http\Message\Response
|
||||||
* @throws InvalidArgumentException If the HTTP handshake is mal-formed
|
|
||||||
* @throws UnderflowException If the message hasn't finished buffering (not yet implemented, theoretically will only happen with Hixie version)
|
* @throws UnderflowException If the message hasn't finished buffering (not yet implemented, theoretically will only happen with Hixie version)
|
||||||
*/
|
*/
|
||||||
function handshake(RequestInterface $request);
|
function handshake(RequestInterface $request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Ratchet\ConnectionInterface
|
||||||
|
* @param Ratchet\MessageInterface
|
||||||
|
* @return Ratchet\ConnectionInterface
|
||||||
|
*/
|
||||||
|
function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return MessageInterface
|
* @return MessageInterface
|
||||||
*/
|
*/
|
||||||
function newMessage();
|
//function newMessage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return FrameInterface
|
* @return FrameInterface
|
||||||
*/
|
*/
|
||||||
function newFrame();
|
//function newFrame();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string
|
* @param string
|
||||||
|
@ -61,7 +61,7 @@ class WsServer implements MessageComponentInterface {
|
|||||||
$this->versioner
|
$this->versioner
|
||||||
->enableVersion(new Version\RFC6455($component))
|
->enableVersion(new Version\RFC6455($component))
|
||||||
->enableVersion(new Version\HyBi10($component))
|
->enableVersion(new Version\HyBi10($component))
|
||||||
//->enableVersion(new Version\Hixie76)
|
->enableVersion(new Version\Hixie76)
|
||||||
;
|
;
|
||||||
|
|
||||||
$this->_decorating = $component;
|
$this->_decorating = $component;
|
||||||
|
@ -57,7 +57,7 @@ class HyBi10Test extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
public function testUnframeMatchesPreFraming() {
|
public function testUnframeMatchesPreFraming() {
|
||||||
$string = 'Hello World!';
|
$string = 'Hello World!';
|
||||||
$framed = $this->_version->frame($string);
|
$framed = $this->_version->newFrame($string)->getContents();
|
||||||
|
|
||||||
$frame = new Frame;
|
$frame = new Frame;
|
||||||
$frame->addBuffer($framed);
|
$frame->addBuffer($framed);
|
||||||
|
@ -60,11 +60,4 @@ class MessageTest extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
$this->assertEquals(28, $this->message->getPayloadLength());
|
$this->assertEquals(28, $this->message->getPayloadLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testToString() {
|
|
||||||
$msg = 'Who likes short shorts?';
|
|
||||||
$this->message->addFrame(Frame::create($msg));
|
|
||||||
|
|
||||||
$this->assertEquals($msg, (string)$this->message);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -50,7 +50,7 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
public function testUnframeMatchesPreFraming() {
|
public function testUnframeMatchesPreFraming() {
|
||||||
$string = 'Hello World!';
|
$string = 'Hello World!';
|
||||||
$framed = $this->version->frame($string);
|
$framed = $this->version->newFrame($string)->getContents();
|
||||||
|
|
||||||
$frame = new Frame;
|
$frame = new Frame;
|
||||||
$frame->addBuffer($framed);
|
$frame->addBuffer($framed);
|
||||||
|
Loading…
Reference in New Issue
Block a user