Replace slow validator with preg_match UTF8 check
This commit is contained in:
parent
4f15d6558e
commit
59a30c3b72
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\RFC6455\Encoding;
|
|
||||||
|
|
||||||
class NullValidator implements ValidatorInterface {
|
|
||||||
/**
|
|
||||||
* What value to return when checkEncoding is valid
|
|
||||||
* @var boolean
|
|
||||||
*/
|
|
||||||
public $validationResponse = true;
|
|
||||||
|
|
||||||
public function checkEncoding($str, $encoding) {
|
|
||||||
return (boolean)$this->validationResponse;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\RFC6455\Encoding;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated - Use NullValidator
|
|
||||||
*/
|
|
||||||
class ToggleableValidator implements ValidatorInterface {
|
|
||||||
/**
|
|
||||||
* Toggle if checkEncoding checks the encoding or not
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $on;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Validator
|
|
||||||
*/
|
|
||||||
private $validator;
|
|
||||||
|
|
||||||
public function __construct($on = true) {
|
|
||||||
$this->validator = new Validator;
|
|
||||||
$this->on = (boolean)$on;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function checkEncoding($str, $encoding) {
|
|
||||||
if (!(boolean)$this->on) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->validator->checkEncoding($str, $encoding);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\RFC6455\Encoding;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class handled encoding validation
|
|
||||||
*/
|
|
||||||
class Validator implements ValidatorInterface {
|
|
||||||
const UTF8_ACCEPT = 0;
|
|
||||||
const UTF8_REJECT = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incremental UTF-8 validator with constant memory consumption (minimal state).
|
|
||||||
*
|
|
||||||
* Implements the algorithm "Flexible and Economical UTF-8 Decoder" by
|
|
||||||
* Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/).
|
|
||||||
*/
|
|
||||||
protected static $dfa = array(
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 00..1f
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 20..3f
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 40..5f
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 60..7f
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, # 80..9f
|
|
||||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, # a0..bf
|
|
||||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, # c0..df
|
|
||||||
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, # e0..ef
|
|
||||||
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, # f0..ff
|
|
||||||
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, # s0..s0
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, # s1..s2
|
|
||||||
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, # s3..s4
|
|
||||||
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, # s5..s6
|
|
||||||
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # s7..s8
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup if mbstring is available
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $hasMbString = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup if iconv is available
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $hasIconv = false;
|
|
||||||
|
|
||||||
public function __construct() {
|
|
||||||
$this->hasMbString = extension_loaded('mbstring');
|
|
||||||
$this->hasIconv = extension_loaded('iconv');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $str The value to check the encoding
|
|
||||||
* @param string $against The type of encoding to check against
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function checkEncoding($str, $against) {
|
|
||||||
if ('UTF-8' === $against) {
|
|
||||||
return $this->isUtf8($str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->hasMbString) {
|
|
||||||
return mb_check_encoding($str, $against);
|
|
||||||
} elseif ($this->hasIconv) {
|
|
||||||
return ($str === iconv($against, "{$against}//IGNORE", $str));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isUtf8($str) {
|
|
||||||
if ($this->hasMbString) {
|
|
||||||
if (false === mb_check_encoding($str, 'UTF-8')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} elseif ($this->hasIconv) {
|
|
||||||
if ($str !== iconv('UTF-8', 'UTF-8//IGNORE', $str)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$state = static::UTF8_ACCEPT;
|
|
||||||
|
|
||||||
for ($i = 0, $len = strlen($str); $i < $len; $i++) {
|
|
||||||
$state = static::$dfa[256 + ($state << 4) + static::$dfa[ord($str[$i])]];
|
|
||||||
|
|
||||||
if (static::UTF8_REJECT === $state) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Ratchet\RFC6455\Encoding;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Probably move this into Messaging\Validation
|
|
||||||
*/
|
|
||||||
interface ValidatorInterface {
|
|
||||||
/**
|
|
||||||
* Verify a string matches the encoding type
|
|
||||||
* @param string $str The string to check
|
|
||||||
* @param string $encoding The encoding type to check against
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function checkEncoding($str, $encoding);
|
|
||||||
}
|
|
@ -2,7 +2,6 @@
|
|||||||
namespace Ratchet\RFC6455\Handshake;
|
namespace Ratchet\RFC6455\Handshake;
|
||||||
use Psr\Http\Message\RequestInterface;
|
use Psr\Http\Message\RequestInterface;
|
||||||
use GuzzleHttp\Psr7\Response;
|
use GuzzleHttp\Psr7\Response;
|
||||||
use Ratchet\RFC6455\Encoding\ValidatorInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The latest version of the WebSocket protocol
|
* The latest version of the WebSocket protocol
|
||||||
@ -14,19 +13,12 @@ class Negotiator implements NegotiatorInterface {
|
|||||||
*/
|
*/
|
||||||
private $verifier;
|
private $verifier;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \Ratchet\RFC6455\Encoding\ValidatorInterface
|
|
||||||
*/
|
|
||||||
private $validator;
|
|
||||||
|
|
||||||
private $_supportedSubProtocols = [];
|
private $_supportedSubProtocols = [];
|
||||||
|
|
||||||
private $_strictSubProtocols = true;
|
private $_strictSubProtocols = true;
|
||||||
|
|
||||||
public function __construct(ValidatorInterface $validator) {
|
public function __construct() {
|
||||||
$this->verifier = new RequestVerifier;
|
$this->verifier = new RequestVerifier;
|
||||||
|
|
||||||
$this->validator = $validator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\RFC6455\Messaging\Streaming;
|
namespace Ratchet\RFC6455\Messaging\Streaming;
|
||||||
use Ratchet\RFC6455\Encoding\ValidatorInterface;
|
|
||||||
use Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker;
|
use Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker;
|
||||||
use Ratchet\RFC6455\Messaging\Protocol\MessageInterface;
|
use Ratchet\RFC6455\Messaging\Protocol\MessageInterface;
|
||||||
use Ratchet\RFC6455\Messaging\Protocol\FrameInterface;
|
use Ratchet\RFC6455\Messaging\Protocol\FrameInterface;
|
||||||
@ -8,11 +7,6 @@ use Ratchet\RFC6455\Messaging\Protocol\Message;
|
|||||||
use Ratchet\RFC6455\Messaging\Protocol\Frame;
|
use Ratchet\RFC6455\Messaging\Protocol\Frame;
|
||||||
|
|
||||||
class MessageStreamer {
|
class MessageStreamer {
|
||||||
/**
|
|
||||||
* @var \Ratchet\RFC6455\Encoding\ValidatorInterface
|
|
||||||
*/
|
|
||||||
private $validator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker
|
* @var \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker
|
||||||
*/
|
*/
|
||||||
@ -49,14 +43,12 @@ class MessageStreamer {
|
|||||||
private $checkForMask;
|
private $checkForMask;
|
||||||
|
|
||||||
function __construct(
|
function __construct(
|
||||||
ValidatorInterface $encodingValidator,
|
|
||||||
CloseFrameChecker $frameChecker,
|
CloseFrameChecker $frameChecker,
|
||||||
callable $onMessage,
|
callable $onMessage,
|
||||||
callable $onControl = null,
|
callable $onControl = null,
|
||||||
$expectMask = true,
|
$expectMask = true,
|
||||||
$exceptionFactory = null
|
$exceptionFactory = null
|
||||||
) {
|
) {
|
||||||
$this->validator = $encodingValidator;
|
|
||||||
$this->closeFrameChecker = $frameChecker;
|
$this->closeFrameChecker = $frameChecker;
|
||||||
$this->checkForMask = (bool)$expectMask;
|
$this->checkForMask = (bool)$expectMask;
|
||||||
|
|
||||||
@ -166,7 +158,7 @@ class MessageStreamer {
|
|||||||
return $this->newCloseFrame(Frame::CLOSE_PROTOCOL);
|
return $this->newCloseFrame(Frame::CLOSE_PROTOCOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->validator->checkEncoding(substr($bin, 2), 'UTF-8')) {
|
if (!preg_match('//u', substr($bin, 2))) {
|
||||||
return $this->newCloseFrame(Frame::CLOSE_BAD_PAYLOAD);
|
return $this->newCloseFrame(Frame::CLOSE_BAD_PAYLOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +193,7 @@ class MessageStreamer {
|
|||||||
*/
|
*/
|
||||||
public function checkMessage(MessageInterface $message) {
|
public function checkMessage(MessageInterface $message) {
|
||||||
if (!$message->isBinary()) {
|
if (!$message->isBinary()) {
|
||||||
if (!$this->validator->checkEncoding($message->getPayload(), 'UTF-8')) {
|
if (!preg_match('//u', $message->getPayload())) {
|
||||||
return Frame::CLOSE_BAD_PAYLOAD;
|
return Frame::CLOSE_BAD_PAYLOAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ $factory = new \React\SocketClient\Connector($loop, $dnsResolver);
|
|||||||
function echoStreamerFactory($conn)
|
function echoStreamerFactory($conn)
|
||||||
{
|
{
|
||||||
return new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
return new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
||||||
new \Ratchet\RFC6455\Encoding\Validator,
|
|
||||||
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
||||||
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($conn) {
|
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($conn) {
|
||||||
/** @var Frame $frame */
|
/** @var Frame $frame */
|
||||||
@ -72,7 +71,6 @@ function getTestCases() {
|
|||||||
$deferred->reject();
|
$deferred->reject();
|
||||||
} else {
|
} else {
|
||||||
$ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
$ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
||||||
new \Ratchet\RFC6455\Encoding\Validator,
|
|
||||||
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
||||||
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) {
|
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) {
|
||||||
$deferred->resolve($msg->getPayload());
|
$deferred->resolve($msg->getPayload());
|
||||||
@ -180,7 +178,6 @@ function createReport() {
|
|||||||
$deferred->reject();
|
$deferred->reject();
|
||||||
} else {
|
} else {
|
||||||
$ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
$ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
||||||
new \Ratchet\RFC6455\Encoding\Validator,
|
|
||||||
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
||||||
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) {
|
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) {
|
||||||
$deferred->resolve($msg->getPayload());
|
$deferred->resolve($msg->getPayload());
|
||||||
|
@ -10,13 +10,12 @@ $loop = \React\EventLoop\Factory::create();
|
|||||||
$socket = new \React\Socket\Server($loop);
|
$socket = new \React\Socket\Server($loop);
|
||||||
$server = new \React\Http\Server($socket);
|
$server = new \React\Http\Server($socket);
|
||||||
|
|
||||||
$encodingValidator = new \Ratchet\RFC6455\Encoding\Validator;
|
|
||||||
$closeFrameChecker = new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker;
|
$closeFrameChecker = new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker;
|
||||||
$negotiator = new \Ratchet\RFC6455\Handshake\Negotiator($encodingValidator);
|
$negotiator = new \Ratchet\RFC6455\Handshake\Negotiator;
|
||||||
|
|
||||||
$uException = new \UnderflowException;
|
$uException = new \UnderflowException;
|
||||||
|
|
||||||
$server->on('request', function (\React\Http\Request $request, \React\Http\Response $response) use ($negotiator, $encodingValidator, $closeFrameChecker, $uException) {
|
$server->on('request', function (\React\Http\Request $request, \React\Http\Response $response) use ($negotiator, $closeFrameChecker, $uException) {
|
||||||
$psrRequest = new \GuzzleHttp\Psr7\Request($request->getMethod(), $request->getPath(), $request->getHeaders());
|
$psrRequest = new \GuzzleHttp\Psr7\Request($request->getMethod(), $request->getPath(), $request->getHeaders());
|
||||||
|
|
||||||
$negotiatorResponse = $negotiator->handshake($psrRequest);
|
$negotiatorResponse = $negotiator->handshake($psrRequest);
|
||||||
@ -34,7 +33,7 @@ $server->on('request', function (\React\Http\Request $request, \React\Http\Respo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parser = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer($encodingValidator, $closeFrameChecker, function(MessageInterface $message) use ($response) {
|
$parser = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer($closeFrameChecker, function(MessageInterface $message) use ($response) {
|
||||||
$response->write($message->getContents());
|
$response->write($message->getContents());
|
||||||
}, function(FrameInterface $frame) use ($response, &$parser) {
|
}, function(FrameInterface $frame) use ($response, &$parser) {
|
||||||
switch ($frame->getOpCode()) {
|
switch ($frame->getOpCode()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user