Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome 20 websocket handshake

I'am using PHP Websocket server by lemmingzshadow (web). Everything worked just fine till now.

After update to chrome 20, if I want to do handshake with server it ends with this error

Error during WebSocket handshake: Sec-WebSocket-Protocol mismatch 

Headers from chrome 20

GET /demo HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: gomokulive.eu:8001
Origin: http://www.gomokulive.eu
Sec-WebSocket-Key: s+AMQQu4Q10xH2AKy49byg==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame

Headers sent back:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: dMCVYKkF5VRrIouWFW7EYdvfD28=
Sec-WebSocket-Protocol: demo

I think problem is with "Sec-WebSocket-Extensions: x-webkit-deflate-frame" header from Chrome 20.

Any idea how to get it working again?

like image 773
m4recek Avatar asked Jul 02 '12 20:07

m4recek


3 Answers

The server is violating the WebSocket protocol. It's likely that Chrome is just adhering to the standard more correctly in version 20 and that is revealing a bug in the server.

The problem is that the server is sending back a "Sec-WebSocket-Protocol" header in the response but this is only legal if the client sends the same header in the request. If the client does not send the Sec-WebSocket-Protocol then the server should omit the header in the response.

See the /subprotocol/ description on page 22 in Section 4.2.2 of rfc6455

like image 167
kanaka Avatar answered Nov 04 '22 03:11

kanaka


A quick fix for php-websocket would be:

$response.= "Sec-WebSocket-Accept: " . $secAccept . "\r\n";
if (isset($headers['Sec-WebSocket-Protocol']))
{
    $response.= "Sec-WebSocket-Protocol: " . substr($path, 1) . "\r\n";
}
$response .= "\r\n";
like image 40
Dejan Marjanović Avatar answered Nov 04 '22 03:11

Dejan Marjanović


An EASY way to fix is add Sec-WebSocket-Accept information when do_handshake, code as below:

    list($resource,$host,$origin,$key) = $this->getheaders($buffer);

    $accept = base64_encode(SHA1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));

    $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
            "Upgrade: WebSocket\r\n" .
            "Connection: Upgrade\r\n" .
            "WebSocket-Origin: {$origin}\r\n" .
            "WebSocket-Location: ws://{$host}{$resource}\r\n".
            "Sec-WebSocket-Accept: " . $accept . "\r\n\r\n";
    $this->handshakes[$socket_index] = true;

    socket_write($socket,$upgrade,strlen($upgrade));

where,

$accept = base64_encode(SHA1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));

$key is Sec-WebSocket-Key got from $buffer, you can print_r($buffer) to have a look.

Hope this can solve your problem..

like image 1
navins Avatar answered Nov 04 '22 05:11

navins