Completed
Pull Request — master (#100)
by Maxime
03:53
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
    public function verify(AbstractHttpMessage $request, string $key = null)
40
    {
41
        if (!$request instanceof Request) {
42
            throw new RuntimeException(
43
                sprintf('The client handshake cannot verify something else than a Response object, %s given.', get_class($response))
44
            );
45
        }
46
47
        if ($request->getHttpVersion() !== 'HTTP/1.1') {
48
            throw new WebsocketException(
49
                \sprintf('Wrong http version, HTTP/1.1 expected, "%s" received.', $request->getHttpVersion())
50
            );
51
        }
52
53
        if ($request->getMethod() !== 'GET') {
54
            throw new WebsocketException(
55
                \sprintf('Wrong http method, GET expected, "%" received.', $request->getMethod())
56
            );
57
        }
58
59
        $headers = $request->getHeaders();
60
        if (empty($headers['Sec-WebSocket-Key'])) {
61
            throw new WebsocketException(
62
                \sprintf('Missing websocket key header.')
63
            );
64
        }
65
66
        if (empty($headers['Upgrade']) || 'websocket' !== \strtolower($headers['Upgrade'])) {
67
            throw new WebsocketException(
68
                \sprintf('Wrong or missing upgrade header.')
69
            );
70
        }
71
72
        $version = $headers->get('Sec-WebSocket-Version');
73
        if (!\in_array($version, ServerHandshake::SUPPORTED_VERSIONS)) {
74
            throw new WebsocketVersionException(sprintf('Version %s not supported by Woketo for now.', $version));
75
        }
76
77
        return true;
78
    }
79
80
    /**
81
     * @param Request $request
82
     * @return string
83
     * @throws WebsocketException
84
     */
85
    public function extractKeyFromRequest(Request $request)
86
    {
87
        $key = $request->getHeader('Sec-WebSocket-Key');
88
89
        if (empty($key)) {
90
            throw new WebsocketException('No key found in the request.');
91
        }
92
93
        return $key;
94
    }
95
}