[WebSocket] RFC Masking
Full un/masking capabilities on RFC6455 Frames
This commit is contained in:
parent
9f0e29fe7f
commit
3a530c8c24
@ -179,13 +179,7 @@ class Frame implements FrameInterface {
|
|||||||
throw new \InvalidArgumentException("Masking key MUST be ASCII");
|
throw new \InvalidArgumentException("Masking key MUST be ASCII");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->isCoalesced()) {
|
|
||||||
throw new \UnderflowException('Frame must be coalesced to apply a mask');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isMasked()) {
|
|
||||||
$this->unMaskPayload();
|
$this->unMaskPayload();
|
||||||
}
|
|
||||||
|
|
||||||
$byte = sprintf('%08b', ord(substr($this->data, 1, 1)));
|
$byte = sprintf('%08b', ord(substr($this->data, 1, 1)));
|
||||||
|
|
||||||
@ -193,16 +187,7 @@ class Frame implements FrameInterface {
|
|||||||
$this->data = substr_replace($this->data, $maskingKey, $this->getNumPayloadBytes() + 1, 0);
|
$this->data = substr_replace($this->data, $maskingKey, $this->getNumPayloadBytes() + 1, 0);
|
||||||
|
|
||||||
$this->_bytes_rec += static::MASK_LENGTH;
|
$this->_bytes_rec += static::MASK_LENGTH;
|
||||||
|
$this->data = substr_replace($this->data, $this->applyMaskToPayload($maskingKey), $this->getPayloadStartingByte(), $this->getPayloadLength());
|
||||||
$plLen = $this->getPayloadLength();
|
|
||||||
$start = $this->getPayloadStartingByte();
|
|
||||||
$maskedPl = '';
|
|
||||||
|
|
||||||
for ($i = 0; $i < $plLen; $i++) {
|
|
||||||
$maskedPl .= substr($this->data, $i + $start, 1) ^ substr($maskingKey, $i % static::MASK_LENGTH, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->data = substr_replace($this->data, $maskedPl, $start, $plLen);
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -217,18 +202,33 @@ class Frame implements FrameInterface {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$maskingKey = $this->getMaskingKey();
|
||||||
|
|
||||||
|
$byte = sprintf('%08b', ord(substr($this->data, 1, 1)));
|
||||||
|
|
||||||
|
$this->data = substr_replace($this->data, static::encode(substr_replace($byte, '0', 0, 1)), 1, 1);
|
||||||
|
$this->data = substr_replace($this->data, '', $this->getNumPayloadBytes() + 1, static::MASK_LENGTH);
|
||||||
|
|
||||||
|
$this->_bytes_rec -= static::MASK_LENGTH;
|
||||||
|
$this->data = substr_replace($this->data, $this->applyMaskToPayload($maskingKey), $this->getPayloadStartingByte(), $this->getPayloadLength());
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyMaskToPayload($maskingKey) {
|
||||||
if (!$this->isCoalesced()) {
|
if (!$this->isCoalesced()) {
|
||||||
throw new \UnderflowException('Frame must be coalesced to apply a mask');
|
throw new \UnderflowException('Frame must be coalesced to apply a mask');
|
||||||
}
|
}
|
||||||
|
|
||||||
$maskingKey = $this->getMaskingKey();
|
$plLen = $this->getPayloadLength();
|
||||||
|
$start = $this->getPayloadStartingByte();
|
||||||
|
$applied = '';
|
||||||
|
|
||||||
// set the indicator bit to 0
|
for ($i = 0; $i < $plLen; $i++) {
|
||||||
// remove the masking key
|
$applied .= substr($this->data, $i + $start, 1) ^ substr($maskingKey, $i % static::MASK_LENGTH, 1);
|
||||||
// get the masking key
|
}
|
||||||
// unmask the payload
|
|
||||||
|
|
||||||
return $this;
|
return $applied;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -343,17 +343,11 @@ class Frame implements FrameInterface {
|
|||||||
throw new \UnderflowException('Can not return partial message');
|
throw new \UnderflowException('Can not return partial message');
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload = '';
|
|
||||||
$length = $this->getPayloadLength();
|
$length = $this->getPayloadLength();
|
||||||
$start = $this->getPayloadStartingByte();
|
$start = $this->getPayloadStartingByte();
|
||||||
|
|
||||||
if ($this->isMasked()) {
|
if ($this->isMasked()) {
|
||||||
$mask = $this->getMaskingKey();
|
$payload = $this->applyMaskToPayload($this->getMaskingKey());
|
||||||
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
// Double check the RFC - is the masking byte level or character level?
|
|
||||||
$payload .= substr($this->data, $i + $start, 1) ^ substr($mask, $i % static::MASK_LENGTH, 1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$payload = substr($this->data, $start, $this->getPayloadLength());
|
$payload = substr($this->data, $start, $this->getPayloadLength());
|
||||||
}
|
}
|
||||||
|
@ -306,6 +306,14 @@ class FrameTest extends \PHPUnit_Framework_TestCase {
|
|||||||
$this->assertEquals($msg, $frame->getPayload());
|
$this->assertEquals($msg, $frame->getPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUnMaskPayload() {
|
||||||
|
$string = $this->generateRandomString();
|
||||||
|
$frame = Frame::create($string)->maskPayload()->unMaskPayload();
|
||||||
|
|
||||||
|
$this->assertFalse($frame->isMasked());
|
||||||
|
$this->assertEquals($string, $frame->getPayload());
|
||||||
|
}
|
||||||
|
|
||||||
protected function generateRandomString($length = 10, $addSpaces = true, $addNumbers = true) {
|
protected function generateRandomString($length = 10, $addSpaces = true, $addNumbers = true) {
|
||||||
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"$%&/()=[]{}'; // ยง
|
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"$%&/()=[]{}'; // ยง
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user