commit
46f3393ec1
@ -8,6 +8,10 @@ CHANGELOG
|
||||
|
||||
---
|
||||
|
||||
* 0.2.5 (2013-??-??)
|
||||
|
||||
* Fixed Hixie-76 handshake bug
|
||||
|
||||
* 0.2.4 (2013-03-09)
|
||||
|
||||
* Support for Symfony 2.2 and Guzzle 2.3
|
||||
|
@ -7,12 +7,10 @@ class RequestFactory extends GuzzleRequestFactory {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create($method, $url, $headers = null, $body = null) {
|
||||
public function create($method, $url, $headers = null, $body = '') {
|
||||
$c = $this->entityEnclosingRequestClass;
|
||||
$request = new $c($method, $url, $headers);
|
||||
if ($body) {
|
||||
$request->setBody(EntityBody::factory($body));
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ class HttpRequestParser implements MessageInterface {
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEom($message) {
|
||||
//return (static::EOM === substr($message, 0 - strlen(static::EOM)));
|
||||
return (boolean)strpos($message, static::EOM);
|
||||
}
|
||||
}
|
@ -36,9 +36,15 @@ class Hixie76 implements VersionInterface {
|
||||
/**
|
||||
* @param \Guzzle\Http\Message\RequestInterface $request
|
||||
* @return \Guzzle\Http\Message\Response
|
||||
* @throws \UnderflowException If there hasn't been enough data received
|
||||
*/
|
||||
public function handshake(RequestInterface $request) {
|
||||
$body = $this->sign($request->getHeader('Sec-WebSocket-Key1', true), $request->getHeader('Sec-WebSocket-Key2', true), (string)$request->getBody());
|
||||
$body = substr($request->getBody(), 0, 8);
|
||||
if (8 !== strlen($body)) {
|
||||
throw new \UnderflowException("Not enough data received to issue challenge response");
|
||||
}
|
||||
|
||||
$challenge = $this->sign($request->getHeader('Sec-WebSocket-Key1', true), $request->getHeader('Sec-WebSocket-Key2', true), $body);
|
||||
|
||||
$headers = array(
|
||||
'Upgrade' => 'WebSocket'
|
||||
@ -47,7 +53,7 @@ class Hixie76 implements VersionInterface {
|
||||
, 'Sec-WebSocket-Location' => 'ws://' . $request->getHeader('Host', true) . $request->getPath()
|
||||
);
|
||||
|
||||
$response = new Response(101, $headers, $body);
|
||||
$response = new Response(101, $headers, $challenge);
|
||||
$response->setStatus(101, 'WebSocket Protocol Handshake');
|
||||
|
||||
return $response;
|
||||
@ -98,12 +104,10 @@ class Hixie76 implements VersionInterface {
|
||||
|
||||
public function generateKeyNumber($key) {
|
||||
if (0 === substr_count($key, ' ')) {
|
||||
return '';
|
||||
return 0;
|
||||
}
|
||||
|
||||
$int = (int)preg_replace('[\D]', '', $key) / substr_count($key, ' ');
|
||||
|
||||
return (is_int($int)) ? $int : '';
|
||||
return preg_replace('[\D]', '', $key) / substr_count($key, ' ');
|
||||
}
|
||||
|
||||
protected function sign($key1, $key2, $code) {
|
||||
|
@ -4,6 +4,7 @@ use Ratchet\AbstractConnectionDecorator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @property \StdClass $WebSocket
|
||||
*/
|
||||
class Connection extends AbstractConnectionDecorator {
|
||||
public function send($msg) {
|
||||
|
@ -5,6 +5,7 @@ use Ratchet\WebSocket\Version\DataInterface;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @property \StdClass $WebSocket
|
||||
*/
|
||||
class Connection extends AbstractConnectionDecorator {
|
||||
public function send($msg) {
|
||||
|
@ -88,7 +88,13 @@ class WsServer implements MessageComponentInterface {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onMessage(ConnectionInterface $from, $msg) {
|
||||
if (true !== $from->WebSocket->established) {
|
||||
if (true === $from->WebSocket->established) {
|
||||
return $from->WebSocket->version->onMessage($this->connections[$from], $msg);
|
||||
}
|
||||
|
||||
if (isset($from->WebSocket->request)) {
|
||||
$from->WebSocket->request->getBody()->write($msg);
|
||||
} else {
|
||||
try {
|
||||
if (null === ($request = $this->reqParser->onMessage($from, $msg))) {
|
||||
return;
|
||||
@ -103,15 +109,20 @@ class WsServer implements MessageComponentInterface {
|
||||
|
||||
$from->WebSocket->request = $request;
|
||||
$from->WebSocket->version = $this->versioner->getVersion($request);
|
||||
}
|
||||
|
||||
$response = $from->WebSocket->version->handshake($request);
|
||||
$response->setHeader('X-Powered-By', \Ratchet\VERSION);
|
||||
try {
|
||||
$response = $from->WebSocket->version->handshake($from->WebSocket->request);
|
||||
} catch (\UnderflowException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This needs to be refactored later on, incorporated with routing
|
||||
if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($request->getTokenizedHeader('Sec-WebSocket-Protocol', ',')))) {
|
||||
if ('' !== ($agreedSubProtocols = $this->getSubProtocolString($from->WebSocket->request->getTokenizedHeader('Sec-WebSocket-Protocol', ',')))) {
|
||||
$response->setHeader('Sec-WebSocket-Protocol', $agreedSubProtocols);
|
||||
}
|
||||
|
||||
$response->setHeader('X-Powered-By', \Ratchet\VERSION);
|
||||
$from->send((string)$response);
|
||||
|
||||
if (101 != $response->getStatusCode()) {
|
||||
@ -127,9 +138,6 @@ class WsServer implements MessageComponentInterface {
|
||||
return $this->_decorating->onOpen($upgraded);
|
||||
}
|
||||
|
||||
$from->WebSocket->version->onMessage($this->connections[$from], $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -1,11 +1,15 @@
|
||||
<?php
|
||||
namespace Ratchet\Tests\WebSocket\Version;
|
||||
use Ratchet\WebSocket\Version\Hixie76;
|
||||
use Ratchet\WebSocket\WsServer;
|
||||
|
||||
/**
|
||||
* @covers Ratchet\WebSocket\Version\Hixie76
|
||||
*/
|
||||
class Hixie76Test extends \PHPUnit_Framework_TestCase {
|
||||
protected $_crlf = "\r\n";
|
||||
protected $_body = '6dW+XgKfWV0=';
|
||||
|
||||
protected $_version;
|
||||
|
||||
public function setUp() {
|
||||
@ -27,11 +31,53 @@ class Hixie76Test extends \PHPUnit_Framework_TestCase {
|
||||
public static function keyProvider() {
|
||||
return array(
|
||||
array(179922739, '17 9 G`ZD9 2 2b 7X 3 /r90')
|
||||
, array('', '17 9 G`ZD9 2 2b 7X 3 /r91')
|
||||
// , array(906585445, '3e6b263 4 17 80')
|
||||
, array('', '3e6b263 4 17 80')
|
||||
, array('', '3e6b63 4 17 80')
|
||||
, array('', '3e6b6341780')
|
||||
, array(906585445, '3e6b263 4 17 80')
|
||||
, array(0, '3e6b26341780')
|
||||
);
|
||||
}
|
||||
|
||||
public function headerProvider() {
|
||||
$key1 = base64_decode('QTN+ICszNiA2IDJvICBWOG4gNyAgc08yODhZ');
|
||||
$key2 = base64_decode('TzEyICAgeVsgIFFSNDUgM1IgLiAyOFggNC00dn4z');
|
||||
|
||||
$headers = "GET / HTTP/1.1";
|
||||
$headers .= "Upgrade: WebSocket{$this->_crlf}";
|
||||
$headers .= "Connection: Upgrade{$this->_crlf}";
|
||||
$headers .= "Host: home.chrisboden.ca{$this->_crlf}";
|
||||
$headers .= "Origin: http://fiddle.jshell.net{$this->_crlf}";
|
||||
$headers .= "Sec-WebSocket-Key1:17 Z4< F94 N3 7P41 7{$this->_crlf}";
|
||||
$headers .= "Sec-WebSocket-Key2:1 23C3:,2% 1-29 4 f0{$this->_crlf}";
|
||||
$headers .= "(Key3):70:00:EE:6E:33:20:90:69{$this->_crlf}";
|
||||
$headers .= $this->_crlf;
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function testNoUpgradeBeforeBody() {
|
||||
$headers = $this->headerProvider();
|
||||
$body = base64_decode($this->_body);
|
||||
|
||||
$mockConn = $this->getMock('\\Ratchet\\ConnectionInterface');
|
||||
$mockApp = $this->getMock('\\Ratchet\\MessageComponentInterface');
|
||||
|
||||
$server = new WsServer($mockApp);
|
||||
$server->onOpen($mockConn);
|
||||
$mockApp->expects($this->exactly(0))->method('onOpen');
|
||||
$server->onMessage($mockConn, $headers);
|
||||
}
|
||||
|
||||
public function testTcpFragmentedUpgrade() {
|
||||
$headers = $this->headerProvider();
|
||||
$body = base64_decode($this->_body);
|
||||
|
||||
$mockConn = $this->getMock('\\Ratchet\\ConnectionInterface');
|
||||
$mockApp = $this->getMock('\\Ratchet\\MessageComponentInterface');
|
||||
|
||||
$server = new WsServer($mockApp);
|
||||
$server->onOpen($mockConn);
|
||||
$server->onMessage($mockConn, $headers);
|
||||
|
||||
$mockApp->expects($this->once())->method('onOpen');
|
||||
$server->onMessage($mockConn, $body . $this->_crlf . $this->_crlf);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user