protected function receiveClientHandshake(
        array $headers,
        array $supportedProtocols
    ) {
        if (!isset($headers['Host'])) {

            $response
                = "HTTP/1.1 400 Bad Request\r\n"
                . "X-WebSocket-Message: Client request Host header is "
                . "missing.\r\n";

        } elseif (   !isset($headers['Upgrade'])
                  || !in_array('websocket', $this->parseHeaderValue($headers['Upgrade']))
        ) {

            $response
                = "HTTP/1.1 400 Bad Request\r\n"
                . "X-WebSocket-Message: Client request Upgrade header is "
                . "missing or does not contain the 'websocket' product.\r\n";

        } elseif (   !isset($headers['Connection'])
                  || !in_array('upgrade', $this->parseHeaderValue($headers['Connection']))
        ) {

            $response
                = "HTTP/1.1 400 Bad Request\r\n"
                . "X-WebSocket-Message: Client request Connection header is "
                . "missing or does not contain the'Upgrade' token.\r\n";

        } elseif (!isset($headers['Sec-WebSocket-Key'])) {

            $response
                = "HTTP/1.1 400 Bad Request\r\n"
                . "X-WebSocket-Message: Client request Sec-WebSocket-Key "
                . "header is missing.\r\n";

        } elseif (!isset($headers['Sec-WebSocket-Version'])) {

            $response
                = "HTTP/1.1 400 Bad Request\r\n"
                . "X-WebSocket-Message: Client request Sec-WebSocket-Version "
                . "header is missing.\r\n";

        } elseif ($headers['Sec-WebSocket-Version'] !== self::VERSION) {

            $response
                = "HTTP/1.1 426 Upgrade Required\r\n"
                . "Sec-WebSocket-Version: " . self::VERSION . "\r\n"
                . "X-WebSocket-Message: Client request protocol version is "
                . "unsupported.\r\n";

        } else {

            $key     = $headers['Sec-WebSocket-Key'];
            $accept  = $this->getAccept($key);
            $version = $headers['Sec-WebSocket-Version'];

            $response
                = "HTTP/1.1 101 Switching Protocols\r\n"
                . "Upgrade: websocket\r\n"
                . "Connection: Upgrade\r\n"
                . "Sec-WebSocket-Accept: " . $accept . "\r\n";

            if (isset($headers['Sec-WebSocket-Protocol'])) {
                $protocols = explode(',', $headers['Sec-WebSocket-Protocol']);
                $protocols = array_map('trim', $protocols);

                $supportedProtocol = $this->getSupportedProtocol(
                    $supportedProtocols,
                    $protocols
                );

                // If no protocol is agreed upon, don't send a protocol header
                // in the response. It it up to the client to fail the
                // connection if no protocols are agreed upon. See RFC 6455
                // Section 4.1 server response validation item 6 and Section
                // 4.2.2 /subprotocol/.
                if ($supportedProtocol !== null) {
                    $response
                        .= 'Sec-WebSocket-Protocol: '
                        .  $supportedProtocol . "\r\n";
                }
            }

        }

        $response .= "\r\n";

        return $response;
    }