-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHandshake.php
More file actions
85 lines (65 loc) · 2.28 KB
/
Copy pathHandshake.php
File metadata and controls
85 lines (65 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php
declare(strict_types=1);
namespace Micilini\PhpSockets\Protocol;
final class Handshake
{
private const WEBSOCKET_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
public static function acceptKey(string $key): string
{
return base64_encode(sha1($key . self::WEBSOCKET_GUID, true));
}
/**
* @return array<string, string>
*/
public static function parseRequestHeaders(string $request): array
{
$headers = [];
$lines = preg_split('/\r\n|\n|\r/', $request) ?: [];
foreach ($lines as $line) {
if (!str_contains($line, ':')) {
continue;
}
[$name, $value] = explode(':', $line, 2);
$headers[strtolower(trim($name))] = trim($value);
}
return $headers;
}
/**
* @return array<string, string>
*/
public static function validateRequest(string $request): array
{
$headers = self::parseRequestHeaders($request);
if (strtolower($headers['upgrade'] ?? '') !== 'websocket') {
throw new ProtocolException('Invalid WebSocket upgrade header.');
}
if (!str_contains(strtolower($headers['connection'] ?? ''), 'upgrade')) {
throw new ProtocolException('Invalid WebSocket connection header.');
}
$key = $headers['sec-websocket-key'] ?? '';
if (!self::isValidClientKey($key)) {
throw new ProtocolException('Invalid WebSocket client key.');
}
if (($headers['sec-websocket-version'] ?? '13') !== '13') {
throw new ProtocolException('Unsupported WebSocket version.');
}
return $headers;
}
public static function response(string $request): string
{
$headers = self::validateRequest($request);
$accept = self::acceptKey($headers['sec-websocket-key']);
return "HTTP/1.1 101 Switching Protocols\r\n"
. "Upgrade: websocket\r\n"
. "Connection: Upgrade\r\n"
. "Sec-WebSocket-Accept: {$accept}\r\n\r\n";
}
private static function isValidClientKey(string $key): bool
{
if ($key === '') {
return false;
}
$decoded = base64_decode($key, true);
return is_string($decoded) && strlen($decoded) === 16;
}
}