GET / chat HTTP / 1.1To which the server should respond to him:
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ ==
Origin: example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
HTTP / 1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =
Sec-WebSocket-Protocol: chat
$answer = "HTTP/1.1 101 Switching Protocols\r\n" ."Upgrade: websocket\r\n" ."Connection: Upgrade\r\n" ."Sec-WebSocket-Accept: ".$hash."\r\n" ."Sec-WebSocket-Protocol: chat\r\n\r\n"
And the client finally saw him.
$hash = $key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
$hash = sha1($hash,true);
$hash = base64_encode($hash);
GET /chat HTTP/1.1 ... Sec-WebSocket-Version: 25
HTTP/1.1 400 Bad Request ... Sec-WebSocket-Version: 13, 8, 7
Could be so: HTTP/1.1 400 Bad Request ... Sec-WebSocket-Version: 13 Sec-WebSocket-Version: 8, 7
GET /chat HTTP/1.1 ... Sec-WebSocket-Version: 13
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len == 127 | + - - - - - - - - - - - - - - - +-------------------------------+ | |Masking-key, if MASK set to 1 | +-------------------------------+-------------------------------+ | Masking-key (continued) | Payload Data | +-------------------------------- - - - - - - - - - - - - - - - + : Payload Data continued ... : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued ... | +---------------------------------------------------------------+
WebSocket connection to 'ws: //example.com: 10001 / test' failed:That is, the browser saw that the following message was masked, although I knew for sure that the server sent an unmasked frame. After a long carding turnip, it turned out that it was a problem of interoperability between web protocols and ActionScript sockets for flash. In my code, a zero byte "\ 0" was inserted at the end of each message as required by this flash, and accordingly this byte was inserted at the end of each frame or header, and the browser read it as the beginning of the next, because the browser knows the exact length of the frame or where header Thus, the first byte of the next header was "\ 0", and the actual first one shifted to the second, which made the browser indignant.
function decode($data){ $payloadLength = ''; $mask = ''; $unmaskedPayload = ''; $decodedData = array(); // estimate frame type: $firstByteBinary = sprintf('%08b', ord($data[0])); $secondByteBinary = sprintf('%08b', ord($data[1])); $opcode = bindec(substr($firstByteBinary, 4, 4)); $isMasked = ($secondByteBinary[0] == '1') ? true : false; $payloadLength = ord($data[1]) & 127; if($isMasked === false) $this->close(1002);// close connection if unmasked frame is received switch($opcode) { case 1: $decodedData['type'] = 'text'; break;// text frame case 8: $decodedData['type'] = 'close'; break;// connection close frame case 9: $decodedData['type'] = 'ping'; break;// ping frame case 10: $decodedData['type'] = 'pong'; break;// pong frame default: $this->close(1003); break;// Close connection on unknown opcode } if($payloadLength === 126) { $mask = substr($data, 4, 4); $payloadOffset = 8; $dataLength = sprintf('%016b', ord($data[2]).ord($data[3])); $dataLength = base_convert($dataLength,2,10); } elseif($payloadLength === 127) { $mask = substr($data, 10, 4); $payloadOffset = 14; $dataLength = ''; for ($i=2;$i<8;$i++) $dataLength .=sprintf('%08b',ord($data[$i])); $dataLength = base_convert($dataLength,2,10); } else{ $mask = substr($data, 2, 4); $payloadOffset = 6; $dataLength = base_convert(sprintf('%08b',ord($data[1]) & 63),2,10); } if($isMasked === true) { for($i = $payloadOffset; $i < $dataLength+$payloadOffset; $i++){ $j = $i - $payloadOffset; $unmaskedPayload .= $data[$i] ^ $mask[$j % 4]; } $decodedData['payload'] = $unmaskedPayload; } else{ $payloadOffset = $payloadOffset - 4; $decodedData['payload'] = substr($data, $payloadOffset); } $decodedData['offset'] = $payloadOffset; return $decodedData; } // ($frame - ) $recieved = 0; while(strlen($frame)> 0) { $msg = decode($frame); $recieved += strlen($msg['payload'])+ $msg['offset']; $frame = substr($frame,$recieved); }
Source: https://habr.com/ru/post/179585/