From 7933d262696ee3e9442296a228ed6c4d663ce7dd Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 31 Mar 2013 11:20:00 -0400 Subject: [PATCH] [WebSocket] Fixed failing Hixie handshake bug refs #80 --- Guzzle/Http/Message/RequestFactory.php | 6 ++--- Version/Hixie76.php | 10 ++++++-- WsServer.php | 34 ++++++++++++++++---------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/Guzzle/Http/Message/RequestFactory.php b/Guzzle/Http/Message/RequestFactory.php index bd7e490..c1f6b45 100644 --- a/Guzzle/Http/Message/RequestFactory.php +++ b/Guzzle/Http/Message/RequestFactory.php @@ -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)); - } + $request->setBody(EntityBody::factory($body)); return $request; } diff --git a/Version/Hixie76.php b/Version/Hixie76.php index fbb8e1d..4043519 100644 --- a/Version/Hixie76.php +++ b/Version/Hixie76.php @@ -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; diff --git a/WsServer.php b/WsServer.php index 409259b..344e520 100644 --- a/WsServer.php +++ b/WsServer.php @@ -89,26 +89,34 @@ class WsServer implements MessageComponentInterface { */ public function onMessage(ConnectionInterface $from, $msg) { if (true !== $from->WebSocket->established) { - try { - if (null === ($request = $this->reqParser->onMessage($from, $msg))) { - return; + if (isset($from->WebSocket->request)) { + $from->WebSocket->request->getBody()->write($msg); + } else { + try { + if (null === ($request = $this->reqParser->onMessage($from, $msg))) { + return; + } + } catch (\OverflowException $oe) { + return $this->close($from, 413); } - } catch (\OverflowException $oe) { - return $this->close($from, 413); + + if (!$this->versioner->isVersionEnabled($request)) { + return $this->close($from); + } + + $from->WebSocket->request = $request; + $from->WebSocket->version = $this->versioner->getVersion($request); } - if (!$this->versioner->isVersionEnabled($request)) { - return $this->close($from); + try { + $response = $from->WebSocket->version->handshake($from->WebSocket->request); + } catch (\UnderflowException $e) { + return; } - - $from->WebSocket->request = $request; - $from->WebSocket->version = $this->versioner->getVersion($request); - - $response = $from->WebSocket->version->handshake($request); $response->setHeader('X-Powered-By', \Ratchet\VERSION); // 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); }