/** * @param ClientInterface $client * @param Request $request * @param Response $response * @return bool */ public function setupUpgrades(ClientInterface $client, Request $request, Response $response) { if (($upgrade = $request->getHeader('UPGRADE')) === null) { return false; } $sm = $this->getServiceManager(); /** @var ProtocolUpgrader $protocolUpgrader */ if (($protocolUpgrader = $sm->get('ProtocolUpgrader', [$sm], true)) === null) { return false; } $upgrade = strtolower($upgrade); try { $protocolUpgrader->upgrade($upgrade, $this->getCallbackHandler(), $client, $request, $response); } catch (Exception\UnsupportedUpgradeException $e) { $this->getLogger()->info($e->getMessage()); $response->setReturnCode(505, 'HTTP Version Not Supported')->setBody('Expectation Failed')->setHeader('Connection', 'close')->send($client); } catch (Exception\BadRequestException $e) { $this->getLogger()->info($e->getMessage()); $response->setReturnCode(400, 'Bad Request')->setBody('Bad Request')->setHeader('Connection', 'close')->send($client); } $this->getLogger()->debug('Upgrades set up.'); return true; }
/** * Process WebSocket handshake * * @param ClientInterface $client * @param Http\Request $request * @param Http\Response $response * @return ProtocolUpgradeAwareInterface * @throws \Gplanchat\Io\Net\Protocol\Http\Exception\BadRequestException */ public function upgrade(ClientInterface $client, Http\Request $request, Http\Response $response) { if (($connectionHeader = $request->getHeader('CONNECTION')) === null) { throw new Exception\BadRequestException('Header Connection required.'); } $connectionParams = preg_split('#\\s*,\\s*#', strtolower($request->getHeader('CONNECTION')), PREG_SPLIT_NO_EMPTY); foreach ($connectionParams as &$param) { $param = strtolower($param); } unset($param); if (!in_array('upgrade', $connectionParams)) { throw new Exception\BadRequestException('Header Connection required or invalid value provided.'); } if (($securityKey = $request->getHeader('SEC_WEBSOCKET_KEY')) === null || !preg_match('#[A-Za-z0-9+/]{22}==#', $securityKey, $m)) { throw new Exception\BadRequestException('Header Sec-WebSocket-Key required or invalid value provided.'); } // $client->getDataStore('WebSocket')->set('securityKey', $securityKey); if (($protocolVersion = $request->getHeader('SEC_WEBSOCKET_VERSION')) === null || !in_array($protocolVersion, static::$supportedVersions)) { $response->setReturnCode(426, 'Upgrade Required')->setBody('Upgrade Required')->setHeader('Connection', 'close')->setHeader('Sec-WebSocket-Version', implode(', ', static::$supportedVersions))->send($client); return $this; } // $client->getDataStore('WebSocket')->set('protocolVersion', $protocolVersion); if (($protocol = $request->getHeader('SEC_WEBSOCKET_PROTOCOL')) !== null) { $protocolList = preg_split('#\\s*,\\s*#', strtolower($protocol), PREG_SPLIT_NO_EMPTY); // $client->getDataStore('WebSocket')->set('protocols', $protocolList); $this->emit(new Event('registerProtocols'), [$protocolList]); } if (($extension = $request->getHeader('SEC_WEBSOCKET_EXTENSIONS')) !== null) { $extensionList = preg_split('#\\s*,\\s*#', strtolower($extension), PREG_SPLIT_NO_EMPTY); // $client->getDataStore('WebSocket')->set('extensions', $extensionList); $this->emit(new Event('registerExtensions'), [$extensionList]); } $hashHandler = hash_init('sha1'); hash_update($hashHandler, $securityKey); hash_update($hashHandler, static::SECURITY_GUID); $hash = base64_encode(hash_final($hashHandler, true)); // $this->getLogger()->info('Switching to WebSocket'); $response->setReturnCode(101, 'Switching Protocols')->setHeader('Upgrade', 'websocket')->setHeader('Connection', 'Upgrade')->setHeader('Sec-WebSocket-Accept', $hash)->send($client); return $this; }