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;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Ratchet\RFC6455\Encoding\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* The latest version of the WebSocket protocol
|
||||
@ -14,19 +13,12 @@ class Negotiator implements NegotiatorInterface {
|
||||
*/
|
||||
private $verifier;
|
||||
|
||||
/**
|
||||
* @var \Ratchet\RFC6455\Encoding\ValidatorInterface
|
||||
*/
|
||||
private $validator;
|
||||
|
||||
private $_supportedSubProtocols = [];
|
||||
|
||||
private $_strictSubProtocols = true;
|
||||
|
||||
public function __construct(ValidatorInterface $validator) {
|
||||
public function __construct() {
|
||||
$this->verifier = new RequestVerifier;
|
||||
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
namespace Ratchet\RFC6455\Messaging\Streaming;
|
||||
use Ratchet\RFC6455\Encoding\ValidatorInterface;
|
||||
use Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker;
|
||||
use Ratchet\RFC6455\Messaging\Protocol\MessageInterface;
|
||||
use Ratchet\RFC6455\Messaging\Protocol\FrameInterface;
|
||||
@ -8,11 +7,6 @@ use Ratchet\RFC6455\Messaging\Protocol\Message;
|
||||
use Ratchet\RFC6455\Messaging\Protocol\Frame;
|
||||
|
||||
class MessageStreamer {
|
||||
/**
|
||||
* @var \Ratchet\RFC6455\Encoding\ValidatorInterface
|
||||
*/
|
||||
private $validator;
|
||||
|
||||
/**
|
||||
* @var \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker
|
||||
*/
|
||||
@ -49,14 +43,12 @@ class MessageStreamer {
|
||||
private $checkForMask;
|
||||
|
||||
function __construct(
|
||||
ValidatorInterface $encodingValidator,
|
||||
CloseFrameChecker $frameChecker,
|
||||
callable $onMessage,
|
||||
callable $onControl = null,
|
||||
$expectMask = true,
|
||||
$exceptionFactory = null
|
||||
) {
|
||||
$this->validator = $encodingValidator;
|
||||
$this->closeFrameChecker = $frameChecker;
|
||||
$this->checkForMask = (bool)$expectMask;
|
||||
|
||||
@ -166,7 +158,7 @@ class MessageStreamer {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -201,7 +193,7 @@ class MessageStreamer {
|
||||
*/
|
||||
public function checkMessage(MessageInterface $message) {
|
||||
if (!$message->isBinary()) {
|
||||
if (!$this->validator->checkEncoding($message->getPayload(), 'UTF-8')) {
|
||||
if (!preg_match('//u', $message->getPayload())) {
|
||||
return Frame::CLOSE_BAD_PAYLOAD;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ $factory = new \React\SocketClient\Connector($loop, $dnsResolver);
|
||||
function echoStreamerFactory($conn)
|
||||
{
|
||||
return new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
||||
new \Ratchet\RFC6455\Encoding\Validator,
|
||||
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
||||
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($conn) {
|
||||
/** @var Frame $frame */
|
||||
@ -72,7 +71,6 @@ function getTestCases() {
|
||||
$deferred->reject();
|
||||
} else {
|
||||
$ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
||||
new \Ratchet\RFC6455\Encoding\Validator,
|
||||
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
||||
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) {
|
||||
$deferred->resolve($msg->getPayload());
|
||||
@ -180,7 +178,6 @@ function createReport() {
|
||||
$deferred->reject();
|
||||
} else {
|
||||
$ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(
|
||||
new \Ratchet\RFC6455\Encoding\Validator,
|
||||
new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker,
|
||||
function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) {
|
||||
$deferred->resolve($msg->getPayload());
|
||||
|
@ -10,13 +10,12 @@ $loop = \React\EventLoop\Factory::create();
|
||||
$socket = new \React\Socket\Server($loop);
|
||||
$server = new \React\Http\Server($socket);
|
||||
|
||||
$encodingValidator = new \Ratchet\RFC6455\Encoding\Validator;
|
||||
$closeFrameChecker = new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker;
|
||||
$negotiator = new \Ratchet\RFC6455\Handshake\Negotiator($encodingValidator);
|
||||
$negotiator = new \Ratchet\RFC6455\Handshake\Negotiator;
|
||||
|
||||
$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());
|
||||
|
||||
$negotiatorResponse = $negotiator->handshake($psrRequest);
|
||||
@ -34,7 +33,7 @@ $server->on('request', function (\React\Http\Request $request, \React\Http\Respo
|
||||
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());
|
||||
}, function(FrameInterface $frame) use ($response, &$parser) {
|
||||
switch ($frame->getOpCode()) {
|
||||
|
Loading…
Reference in New Issue
Block a user