Re-use exception

UnderflowExceptions have been used as flow control
Now have a factory to re-throw the same one to not generate a stack trace.
This commit is contained in:
Chris Boden 2015-05-30 23:27:54 -04:00
parent 5cdd8959dc
commit 621b8f836c
2 changed files with 33 additions and 15 deletions

View File

@ -61,12 +61,23 @@ class Frame implements FrameInterface {
*/ */
protected $secondByte = -1; protected $secondByte = -1;
/**
* @var callable
* @returns \UnderflowException
*/
private $ufeg;
/** /**
* @param string|null $payload * @param string|null $payload
* @param bool $final * @param bool $final
* @param int $opcode * @param int $opcode
* @param callable $ufExceptionFactory<\UnderflowException>
*/ */
public function __construct($payload = null, $final = true, $opcode = 1) { public function __construct($payload = null, $final = true, $opcode = 1, callable $ufExceptionFactory = null) {
$this->ufeg = $ufExceptionFactory ?: function($msg = '') {
return new \UnderflowException($msg);
};
if (null === $payload) { if (null === $payload) {
return; return;
} }
@ -132,7 +143,7 @@ class Frame implements FrameInterface {
*/ */
public function isFinal() { public function isFinal() {
if (-1 === $this->firstByte) { if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine if this is the final frame in message'); throw call_user_func($this->ufeg, 'Not enough bytes received to determine if this is the final frame in message');
} }
return 128 === ($this->firstByte & 128); return 128 === ($this->firstByte & 128);
@ -144,7 +155,7 @@ class Frame implements FrameInterface {
*/ */
public function getRsv1() { public function getRsv1() {
if (-1 === $this->firstByte) { if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine reserved bit'); throw call_user_func($this->ufeg, 'Not enough bytes received to determine reserved bit');
} }
return 64 === ($this->firstByte & 64); return 64 === ($this->firstByte & 64);
@ -156,7 +167,7 @@ class Frame implements FrameInterface {
*/ */
public function getRsv2() { public function getRsv2() {
if (-1 === $this->firstByte) { if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine reserved bit'); throw call_user_func($this->ufeg, 'Not enough bytes received to determine reserved bit');
} }
return 32 === ($this->firstByte & 32); return 32 === ($this->firstByte & 32);
@ -168,7 +179,7 @@ class Frame implements FrameInterface {
*/ */
public function getRsv3() { public function getRsv3() {
if (-1 === $this->firstByte) { if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine reserved bit'); throw call_user_func($this->ufeg, 'Not enough bytes received to determine reserved bit');
} }
return 16 == ($this->firstByte & 16); return 16 == ($this->firstByte & 16);
@ -179,7 +190,7 @@ class Frame implements FrameInterface {
*/ */
public function isMasked() { public function isMasked() {
if (-1 === $this->secondByte) { if (-1 === $this->secondByte) {
throw new \UnderflowException("Not enough bytes received ({$this->bytesRecvd}) to determine if mask is set"); throw call_user_func($this->ufeg, "Not enough bytes received ({$this->bytesRecvd}) to determine if mask is set");
} }
return 128 === ($this->secondByte & 128); return 128 === ($this->secondByte & 128);
@ -196,7 +207,7 @@ class Frame implements FrameInterface {
$start = 1 + $this->getNumPayloadBytes(); $start = 1 + $this->getNumPayloadBytes();
if ($this->bytesRecvd < $start + static::MASK_LENGTH) { if ($this->bytesRecvd < $start + static::MASK_LENGTH) {
throw new \UnderflowException('Not enough data buffered to calculate the masking key'); throw call_user_func($this->ufeg, 'Not enough data buffered to calculate the masking key');
} }
return substr($this->data, $start, static::MASK_LENGTH); return substr($this->data, $start, static::MASK_LENGTH);
@ -256,7 +267,7 @@ class Frame implements FrameInterface {
*/ */
public function unMaskPayload() { public function unMaskPayload() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowException('Frame must be coalesced before applying mask'); throw call_user_func($this->ufeg, 'Frame must be coalesced before applying mask');
} }
if (!$this->isMasked()) { if (!$this->isMasked()) {
@ -286,7 +297,7 @@ class Frame implements FrameInterface {
public function applyMask($maskingKey, $payload = null) { public function applyMask($maskingKey, $payload = null) {
if (null === $payload) { if (null === $payload) {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowException('Frame must be coalesced to apply a mask'); throw call_user_func($this->ufeg, 'Frame must be coalesced to apply a mask');
} }
$payload = substr($this->data, $this->getPayloadStartingByte(), $this->getPayloadLength()); $payload = substr($this->data, $this->getPayloadStartingByte(), $this->getPayloadLength());
@ -305,7 +316,7 @@ class Frame implements FrameInterface {
*/ */
public function getOpcode() { public function getOpcode() {
if (-1 === $this->firstByte) { if (-1 === $this->firstByte) {
throw new \UnderflowException('Not enough bytes received to determine opcode'); throw call_user_func($this->ufeg, 'Not enough bytes received to determine opcode');
} }
return ($this->firstByte & ~240); return ($this->firstByte & ~240);
@ -318,7 +329,7 @@ class Frame implements FrameInterface {
*/ */
protected function getFirstPayloadVal() { protected function getFirstPayloadVal() {
if (-1 === $this->secondByte) { if (-1 === $this->secondByte) {
throw new \UnderflowException('Not enough bytes received'); throw call_user_func($this->ufeg, 'Not enough bytes received');
} }
return $this->secondByte & 127; return $this->secondByte & 127;
@ -330,7 +341,7 @@ class Frame implements FrameInterface {
*/ */
protected function getNumPayloadBits() { protected function getNumPayloadBits() {
if (-1 === $this->secondByte) { if (-1 === $this->secondByte) {
throw new \UnderflowException('Not enough bytes received'); throw call_user_func($this->ufeg, 'Not enough bytes received');
} }
// By default 7 bits are used to describe the payload length // By default 7 bits are used to describe the payload length
@ -378,7 +389,7 @@ class Frame implements FrameInterface {
$byte_length = $this->getNumPayloadBytes(); $byte_length = $this->getNumPayloadBytes();
if ($this->bytesRecvd < 1 + $byte_length) { if ($this->bytesRecvd < 1 + $byte_length) {
$this->defPayLen = -1; $this->defPayLen = -1;
throw new \UnderflowException('Not enough data buffered to determine payload length'); throw call_user_func($this->ufeg, 'Not enough data buffered to determine payload length');
} }
$len = 0; $len = 0;
@ -405,7 +416,7 @@ class Frame implements FrameInterface {
*/ */
public function getPayload() { public function getPayload() {
if (!$this->isCoalesced()) { if (!$this->isCoalesced()) {
throw new \UnderflowException('Can not return partial message'); throw call_user_func($this->ufeg, 'Can not return partial message');
} }
$payload = substr($this->data, $this->getPayloadStartingByte(), $this->getPayloadLength()); $payload = substr($this->data, $this->getPayloadStartingByte(), $this->getPayloadLength());

View File

@ -11,8 +11,15 @@ class MessageStreamer {
*/ */
private $validator; private $validator;
private $exceptionFactory;
function __construct(ValidatorInterface $encodingValidator, $expectMask = false) { function __construct(ValidatorInterface $encodingValidator, $expectMask = false) {
$this->validator = new MessageValidator($encodingValidator, !$expectMask); $this->validator = new MessageValidator($encodingValidator, !$expectMask);
$exception = new \UnderflowException;
$this->exceptionFactory = function() use ($exception) {
return $exception;
};
} }
@ -90,6 +97,6 @@ class MessageStreamer {
* @return \Ratchet\RFC6455\Messaging\Protocol\FrameInterface * @return \Ratchet\RFC6455\Messaging\Protocol\FrameInterface
*/ */
public function newFrame($payload = null, $final = null, $opcode = null) { public function newFrame($payload = null, $final = null, $opcode = null) {
return new Frame($payload, $final, $opcode); return new Frame($payload, $final, $opcode, $this->exceptionFactory);
} }
} }