Completed
Pull Request — master (#144)
by
unknown
01:58
created

ServerHandshake   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 80
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Test Coverage

Coverage 77.42%

Importance

Changes 0
Metric Value
wmc 12
lcom 0
cbo 5
dl 0
loc 80
ccs 24
cts 31
cp 0.7742
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A sign() 0 10 2
B verify() 0 40 8
A extractKeyFromRequest() 0 10 2
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 2
    public function sign(AbstractHttpMessage $response = null, string $key = null)
29
    {
30 2
        $signature = \base64_encode(\sha1($key . HandshakeInterface::GUID, true));
31
32 2
        if (null !== $response) {
33 1
            $response->addHeader('Sec-WebSocket-Accept', $signature);
34
        }
35
36 2
        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 7
    public function verify(AbstractHttpMessage $request, string $key = null)
50
    {
51 7
        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 7
        if ($request->getHttpVersion() !== 'HTTP/1.1') {
58 1
            throw new WebsocketException(
59 1
                \sprintf('Wrong http version, HTTP/1.1 expected, "%s" received.', $request->getHttpVersion())
60
            );
61
        }
62
63 6
        if ($request->getMethod() !== 'GET') {
64 1
            throw new WebsocketException(
65 1
                \sprintf('Wrong http method, GET expected, "%" received.', $request->getMethod())
66
            );
67
        }
68
69 5
        $headers = $request->getHeaders();
70 5
        if (empty($headers['Sec-WebSocket-Key'])) {
71 1
            throw new WebsocketException(
72 1
                \sprintf('Missing websocket key header.')
73
            );
74
        }
75
76 4
        if (empty($headers['Upgrade']) || 'websocket' !== \strtolower($headers['Upgrade'])) {
77 1
            throw new WebsocketException(
78 1
                \sprintf('Wrong or missing upgrade header.')
79
            );
80
        }
81
82 3
        $version = $headers->get('Sec-WebSocket-Version');
83 3
        if (!\in_array($version, ServerHandshake::SUPPORTED_VERSIONS)) {
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
84 1
            throw new WebsocketVersionException(sprintf('Version %s not supported by Woketo for now.', $version));
85
        }
86
87 2
        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