API docs and message length

RFC6455 Message::getPayloadLenght now returns a value
This commit is contained in:
Chris Boden 2012-04-29 19:20:59 -04:00
parent 852e5777e3
commit 381dd7bab6
6 changed files with 112 additions and 3 deletions

View File

@ -16,6 +16,9 @@ use Guzzle\Http\Message\Response;
* @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 * @link http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
*/ */
class Hixie76 implements VersionInterface { class Hixie76 implements VersionInterface {
/**
* {@inheritdoc}
*/
public static function isProtocol(RequestInterface $request) { public static function isProtocol(RequestInterface $request) {
return !(null === $request->getHeader('Sec-WebSocket-Key2')); return !(null === $request->getHeader('Sec-WebSocket-Key2'));
} }
@ -40,14 +43,23 @@ class Hixie76 implements VersionInterface {
return $response; return $response;
} }
/**
* @return Hixie76\Message
*/
public function newMessage() { public function newMessage() {
return new Hixie76\Message; return new Hixie76\Message;
} }
/**
* @return Hixie76\Frame
*/
public function newFrame() { public function newFrame() {
return new Hixie76\Frame; return new Hixie76\Frame;
} }
/**
* {@inheritdoc}
*/
public function frame($message, $mask = true) { public function frame($message, $mask = true) {
return chr(0) . $message . chr(255); return chr(0) . $message . chr(255);
} }

View File

@ -12,26 +12,44 @@ class Frame implements FrameInterface {
*/ */
protected $_data = ''; protected $_data = '';
/**
* {@inheritdoc}
*/
public function isCoalesced() { public function isCoalesced() {
return (boolean)($this->_data[0] == chr(0) && substr($this->_data, -1) == chr(255)); return (boolean)($this->_data[0] == chr(0) && substr($this->_data, -1) == chr(255));
} }
/**
* {@inheritdoc}
*/
public function addBuffer($buf) { public function addBuffer($buf) {
$this->_data .= (string)$buf; $this->_data .= (string)$buf;
} }
/**
* {@inheritdoc}
*/
public function isFinal() { public function isFinal() {
return true; return true;
} }
/**
* {@inheritdoc}
*/
public function isMasked() { public function isMasked() {
return false; return false;
} }
/**
* {@inheritdoc}
*/
public function getOpcode() { public function getOpcode() {
return 1; return 1;
} }
/**
* {@inheritdoc}
*/
public function getPayloadLength() { public function getPayloadLength() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowException('Not enough of the message has been buffered to determine the length of the payload'); throw new \UnderflowException('Not enough of the message has been buffered to determine the length of the payload');
@ -40,10 +58,16 @@ class Frame implements FrameInterface {
return strlen($this->_data) - 2; return strlen($this->_data) - 2;
} }
/**
* {@inheritdoc}
*/
public function getMaskingKey() { public function getMaskingKey() {
return ''; return '';
} }
/**
* {@inheritdoc}
*/
public function getPayload() { public function getPayload() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
return new \UnderflowException('Not enough data buffered to read payload'); return new \UnderflowException('Not enough data buffered to read payload');

View File

@ -9,10 +9,16 @@ class Message implements MessageInterface {
*/ */
protected $_frame = null; protected $_frame = null;
/**
* {@inheritdoc}
*/
public function __toString() { public function __toString() {
return $this->getPayload(); return $this->getPayload();
} }
/**
* {@inheritdoc}
*/
public function isCoalesced() { public function isCoalesced() {
if (!($this->_frame instanceof FrameInterface)) { if (!($this->_frame instanceof FrameInterface)) {
return false; return false;
@ -21,6 +27,9 @@ class Message implements MessageInterface {
return $this->_frame->isCoalesced(); return $this->_frame->isCoalesced();
} }
/**
* {@inheritdoc}
*/
public function addFrame(FrameInterface $fragment) { public function addFrame(FrameInterface $fragment) {
if (null !== $this->_frame) { if (null !== $this->_frame) {
throw new \OverflowException('Hixie76 does not support multiple framing of messages'); throw new \OverflowException('Hixie76 does not support multiple framing of messages');
@ -29,15 +38,24 @@ class Message implements MessageInterface {
$this->_frame = $fragment; $this->_frame = $fragment;
} }
/**
* {@inheritdoc}
*/
public function getOpcode() { public function getOpcode() {
// Hixie76 only supported text messages // Hixie76 only supported text messages
return 1; return 1;
} }
/**
* {@inheritdoc}
*/
public function getPayloadLength() { public function getPayloadLength() {
throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')'); throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')');
} }
/**
* {@inheritdoc}
*/
public function getPayload() { public function getPayload() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowException('Message has not been fully buffered yet'); throw new \UnderflowException('Message has not been fully buffered yet');

View File

@ -20,14 +20,16 @@ class RFC6455 implements VersionInterface {
$this->_verifier = new HandshakeVerifier; $this->_verifier = new HandshakeVerifier;
} }
/**
* {@inheritdoc}
*/
public static function isProtocol(RequestInterface $request) { public static function isProtocol(RequestInterface $request) {
$version = (int)$request->getHeader('Sec-WebSocket-Version', -1); $version = (int)$request->getHeader('Sec-WebSocket-Version', -1);
return (13 === $version); return (13 === $version);
} }
/** /**
* @return array * {@inheritdoc}
* I kept this as an array and combined in App for future considerations...easier to add a subprotol as a key value than edit a string
* @todo Decide what to do on failure...currently throwing an exception and I think socket connection is closed. Should be sending 40x error - but from where? * @todo Decide what to do on failure...currently throwing an exception and I think socket connection is closed. Should be sending 40x error - but from where?
*/ */
public function handshake(RequestInterface $request) { public function handshake(RequestInterface $request) {
@ -62,6 +64,7 @@ class RFC6455 implements VersionInterface {
* Thanks to @lemmingzshadow for the code on decoding a HyBi-10 frame * Thanks to @lemmingzshadow for the code on decoding a HyBi-10 frame
* @link https://github.com/lemmingzshadow/php-websocket * @link https://github.com/lemmingzshadow/php-websocket
* @todo look into what happens when false is returned here * @todo look into what happens when false is returned here
* @todo This is needed when a client is created - needs re-write as missing parts of protocol
* @param string * @param string
* @return string * @return string
*/ */

View File

@ -27,6 +27,9 @@ class Frame implements FrameInterface {
*/ */
protected $_pay_check = -1; protected $_pay_check = -1;
/**
* {@inheritdoc}
*/
public function isCoalesced() { public function isCoalesced() {
try { try {
$payload_length = $this->getPayloadLength(); $payload_length = $this->getPayloadLength();
@ -38,6 +41,9 @@ class Frame implements FrameInterface {
return $payload_length + $payload_start === $this->_bytes_rec; return $payload_length + $payload_start === $this->_bytes_rec;
} }
/**
* {@inheritdoc}
*/
public function addBuffer($buf) { public function addBuffer($buf) {
$buf = (string)$buf; $buf = (string)$buf;
@ -45,6 +51,9 @@ class Frame implements FrameInterface {
$this->_bytes_rec += strlen($buf); $this->_bytes_rec += strlen($buf);
} }
/**
* {@inheritdoc}
*/
public function isFinal() { public function isFinal() {
if ($this->_bytes_rec < 1) { if ($this->_bytes_rec < 1) {
throw new \UnderflowException('Not enough bytes received to determine if this is the final frame in message'); throw new \UnderflowException('Not enough bytes received to determine if this is the final frame in message');
@ -54,6 +63,9 @@ class Frame implements FrameInterface {
return (boolean)(int)$fbb[0]; return (boolean)(int)$fbb[0];
} }
/**
* {@inheritdoc}
*/
public function isMasked() { public function isMasked() {
if ($this->_bytes_rec < 2) { if ($this->_bytes_rec < 2) {
throw new \UnderflowException("Not enough bytes received ({$this->_bytes_rec}) to determine if mask is set"); throw new \UnderflowException("Not enough bytes received ({$this->_bytes_rec}) to determine if mask is set");
@ -62,6 +74,9 @@ class Frame implements FrameInterface {
return (boolean)bindec(substr(sprintf('%08b', ord($this->_data[1])), 0, 1)); return (boolean)bindec(substr(sprintf('%08b', ord($this->_data[1])), 0, 1));
} }
/**
* {@inheritdoc}
*/
public function getOpcode() { public function getOpcode() {
if ($this->_bytes_rec < 1) { if ($this->_bytes_rec < 1) {
throw new \UnderflowException('Not enough bytes received to determine opcode'); throw new \UnderflowException('Not enough bytes received to determine opcode');
@ -125,6 +140,9 @@ class Frame implements FrameInterface {
return (1 + $this->getNumPayloadBits()) / 8; return (1 + $this->getNumPayloadBits()) / 8;
} }
/**
* {@inheritdoc}
*/
public function getPayloadLength() { public function getPayloadLength() {
if ($this->_pay_len_def !== -1) { if ($this->_pay_len_def !== -1) {
return $this->_pay_len_def; return $this->_pay_len_def;
@ -151,6 +169,9 @@ class Frame implements FrameInterface {
return $this->getPayloadLength(); return $this->getPayloadLength();
} }
/**
* {@inheritdoc}
*/
public function getMaskingKey() { public function getMaskingKey() {
if (!$this->isMasked()) { if (!$this->isMasked()) {
return ''; return '';
@ -166,10 +187,16 @@ class Frame implements FrameInterface {
return substr($this->_data, $start, $length); return substr($this->_data, $start, $length);
} }
/**
* {@inheritdoc}
*/
public function getPayloadStartingByte() { public function getPayloadStartingByte() {
return 1 + $this->getNumPayloadBytes() + strlen($this->getMaskingKey()); return 1 + $this->getNumPayloadBytes() + strlen($this->getMaskingKey());
} }
/**
* {@inheritdoc}
*/
public function getPayload() { public function getPayload() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowException('Can not return partial message'); throw new \UnderflowException('Can not return partial message');

View File

@ -13,10 +13,16 @@ class Message implements MessageInterface {
$this->_frames = new \SplDoublyLinkedList; $this->_frames = new \SplDoublyLinkedList;
} }
/**
* {@inheritdoc}
*/
public function __toString() { public function __toString() {
return $this->getPayload(); return $this->getPayload();
} }
/**
* {@inheritdoc}
*/
public function isCoalesced() { public function isCoalesced() {
if (count($this->_frames) == 0) { if (count($this->_frames) == 0) {
return false; return false;
@ -28,6 +34,7 @@ class Message implements MessageInterface {
} }
/** /**
* {@inheritdoc}
* @todo Should I allow addFrame if the frame is not coalesced yet? I believe I'm assuming this class will only receive fully formed frame messages * @todo Should I allow addFrame if the frame is not coalesced yet? I believe I'm assuming this class will only receive fully formed frame messages
* @todo Also, I should perhaps check the type...control frames (ping/pong/close) are not to be considered part of a message * @todo Also, I should perhaps check the type...control frames (ping/pong/close) are not to be considered part of a message
*/ */
@ -35,6 +42,9 @@ class Message implements MessageInterface {
$this->_frames->push($fragment); $this->_frames->push($fragment);
} }
/**
* {@inheritdoc}
*/
public function getOpcode() { public function getOpcode() {
if (count($this->_frames) == 0) { if (count($this->_frames) == 0) {
throw new \UnderflowException('No frames have been added to this message'); throw new \UnderflowException('No frames have been added to this message');
@ -43,10 +53,25 @@ class Message implements MessageInterface {
return $this->_frames->bottom()->getOpcode(); return $this->_frames->bottom()->getOpcode();
} }
/**
* {@inheritdoc}
*/
public function getPayloadLength() { public function getPayloadLength() {
throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')'); $len = 0;
foreach ($this->_frames as $frame) {
try {
$len += $frame->getPayloadLength();
} catch (\UnderflowException $e) {
}
} }
return $len;
}
/**
* {@inheritdoc}
*/
public function getPayload() { public function getPayload() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowMessage('Message has not been put back together yet'); throw new \UnderflowMessage('Message has not been put back together yet');