Completed
Push — master ( e26ab3...1dd3f4 )
by Maxime
9s
created

ServerHandshake::sign()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 8
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
crap 6
1
<?php
2
3
/**
4
 * This file is a part of Woketo package.
5
 *
6
 * (c) Nekland <[email protected]>
7
 *
8
 * For the full license, take a look to the LICENSE file
9
 * on the root directory of this project
10
 */
11
12
namespace Nekland\Woketo\Rfc6455\Handshake;
13
use Nekland\Woketo\Exception\RuntimeException;
14
use Nekland\Woketo\Exception\WebsocketException;
15
use Nekland\Woketo\Exception\WebsocketVersionException;
16
use Nekland\Woketo\Http\AbstractHttpMessage;
17
use Nekland\Woketo\Http\Request;
18
use Nekland\Woketo\Http\Response;
19
20
21
/**
22
 * Class ServerHandshake
23
 *
24
 * This class is highly inspired by ratchetphp/RFC6455.
25
 */
26
class ServerHandshake implements HandshakeInterface
27
{
28
    public function sign(AbstractHttpMessage $response = null, string $key = null)
29
    {
30
        $signature = \base64_encode(\sha1($key . HandshakeInterface::GUID, true));
31
32
        if (null !== $response) {
33
            $response->addHeader('Sec-WebSocket-Accept', $signature);
34
        }
35
36
        return $signature;
37
    }
38
39
    /**
40
     * https://tools.ietf.org/html/rfc6455#section-4.2
41
     * 
42
     * @param AbstractHttpMessage $request
43
     * @param string|null         $key
44
     * @return bool
45
     * @throws RuntimeException
46
     * @throws WebsocketException
47
     * @throws WebsocketVersionException
48
     */
49
    public function verify(AbstractHttpMessage $request, string $key = null)
50
    {
51
        if (!$request instanceof Request) {
52
            throw new RuntimeException(
53
                sprintf('The client handshake cannot verify something else than a Response object, %s given.', get_class($response))
54
            );
55
        }
56
57
        if ($request->getHttpVersion() !== 'HTTP/1.1') {
58
            throw new WebsocketException(
59
                \sprintf('Wrong http version, HTTP/1.1 expected, "%s" received.', $request->getHttpVersion())
60
            );
61
        }
62
63
        if ($request->getMethod() !== 'GET') {
64
            throw new WebsocketException(
65
                \sprintf('Wrong http method, GET expected, "%" received.', $request->getMethod())
66
            );
67
        }
68
69
        $headers = $request->getHeaders();
70
        if (empty($headers['Sec-WebSocket-Key'])) {
71
            throw new WebsocketException(
72
                \sprintf('Missing websocket key header.')
73
            );
74
        }
75
76
        if (empty($headers['Upgrade']) || 'websocket' !== \strtolower($headers['Upgrade'])) {
77
            throw new WebsocketException(
78
                \sprintf('Wrong or missing upgrade header.')
79
            );
80
        }
81
82
        $version = $headers->get('Sec-WebSocket-Version');
83
        if (!\in_array($version, ServerHandshake::SUPPORTED_VERSIONS)) {
84
            throw new WebsocketVersionException(sprintf('Version %s not supported by Woketo for now.', $version));
85
        }
86
87
        return true;
88
    }
89
90
    /**
91
     * @param Request $request
92
     * @return string
93
     * @throws WebsocketException
94
     */
95
    public function extractKeyFromRequest(Request $request)
96
    {
97
        $key = $request->getHeader('Sec-WebSocket-Key');
98
99
        if (empty($key)) {
100
            throw new WebsocketException('No key found in the request.');
101
        }
102
103
        return $key;
104
    }
105
}
106