Completed
Pull Request — master (#243)
by Дмитрий
05:05
created

VE::sendHandshakeReply()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
cc 4
eloc 15
c 3
b 2
f 0
nc 8
nop 1
dl 0
loc 22
rs 8.9197
1
<?php
2
namespace PHPDaemon\Servers\WebSocket\Protocols;
3
4
use PHPDaemon\Core\Daemon;
5
use PHPDaemon\Servers\WebSocket\Connection;
6
7
/**
8
 * Websocket protocol hixie-76
9
 * @see         http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
10
 * @description Deprecated websocket protocol (IETF drafts 'hixie-76' or 'hybi-00')
11
 */
12
class VE extends Connection
13
{
14
    const STRING = 0x00;
15
    const BINARY = 0x80;
16
17
    /**
18
     * Sends a handshake message reply
19
     * @param string Received data (no use in this class)
20
     * @return boolean OK?
21
     */
22
    public function sendHandshakeReply($extraHeaders = '')
23
    {
24
        if (!isset($this->server['HTTP_SEC_WEBSOCKET_ORIGIN'])) {
25
            $this->server['HTTP_SEC_WEBSOCKET_ORIGIN'] = '';
26
        }
27
28
        $this->write(
29
            "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
30
            . "Upgrade: WebSocket\r\n"
31
            . "Connection: Upgrade\r\n"
32
            . "Sec-WebSocket-Origin: " . $this->server['HTTP_ORIGIN'] . "\r\n"
33
            . "Sec-WebSocket-Location: ws://" . $this->server['HTTP_HOST'] . $this->server['REQUEST_URI'] . "\r\n"
34
        );
35
        if ($this->pool->config->expose->value) {
36
            $this->writeln('X-Powered-By: phpDaemon/' . Daemon::$version);
37
        }
38
        if (isset($this->server['HTTP_SEC_WEBSOCKET_PROTOCOL'])) {
39
            $this->writeln("Sec-WebSocket-Protocol: " . $this->server['HTTP_SEC_WEBSOCKET_PROTOCOL']);
40
        }
41
        $this->writeln($extraHeaders);
42
        return true;
43
    }
44
45
    /**
46
     * Computes key for Sec-WebSocket.
47
     * @param string Key
48
     * @return string Result
49
     */
50 View Code Duplication
    protected function _computeKey($key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
    {
52
        $spaces = 0;
53
        $digits = '';
54
55
        for ($i = 0, $s = mb_orig_strlen($key); $i < $s; ++$i) {
56
            $c = mb_orig_substr($key, $i, 1);
57
58
            if ($c === "\x20") {
59
                ++$spaces;
60
            } elseif (ctype_digit($c)) {
61
                $digits .= $c;
62
            }
63
        }
64
65
        if ($spaces > 0) {
66
            $result = (float)floor($digits / $spaces);
67
        } else {
68
            $result = (float)$digits;
69
        }
70
71
        return pack('N', $result);
72
    }
73
74
    /**
75
     * Sends a frame.
76
     * @param  string $data Frame's data.
77
     * @param  string $type Frame's type. ("STRING" OR "BINARY")
0 ignored issues
show
Documentation introduced by
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
78
     * @param  callable $cb Optional. Callback called when the frame is received by client.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
79
     * @callback $cb ( )
80
     * @return boolean         Success.
81
     */
82 View Code Duplication
    public function sendFrame($data, $type = null, $cb = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
    {
84
        if (!$this->handshaked) {
85
            return false;
86
        }
87
88
        if ($this->finished && $type !== 'CONNCLOSE') {
89
            return false;
90
        }
91
92
        if ($type === 'CONNCLOSE') {
93
            if ($cb !== null) {
94
                $cb($this);
95
                return true;
96
            }
97
        }
98
99
        // Binary
100
        $type = $this->getFrameType($type);
101
        if (($type & self::BINARY) === self::BINARY) {
102
            $n = mb_orig_strlen($data);
103
            $len = '';
104
            $pos = 0;
105
106
            char:
107
108
            ++$pos;
109
            $c = $n >> 0 & 0x7F;
110
            $n >>= 7;
111
112
            if ($pos !== 1) {
113
                $c += 0x80;
114
            }
115
116
            if ($c !== 0x80) {
117
                $len = chr($c) . $len;
118
                goto char;
119
            };
120
121
            $this->write(chr(self::BINARY) . $len . $data);
122
        } // String
123
        else {
124
            $this->write(chr(self::STRING) . $data . "\xFF");
125
        }
126
        if ($cb !== null) {
127
            $this->onWriteOnce($cb);
128
        }
129
        return true;
130
    }
131
132
    /**
133
     * Called when new data received
134
     * @return void
135
     */
136
    public function onRead()
137
    {
138 View Code Duplication
        while (($buflen = $this->getInputLength()) >= 2) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
            $hdr = $this->look(10);
140
            $frametype = ord(mb_orig_substr($hdr, 0, 1));
141
            if (($frametype & 0x80) === 0x80) {
142
                $len = 0;
143
                $i = 0;
144
                do {
145
                    if ($buflen < $i + 1) {
146
                        return;
147
                    }
148
                    $b = ord(mb_orig_substr($hdr, ++$i, 1));
149
                    $n = $b & 0x7F;
150
                    $len *= 0x80;
151
                    $len += $n;
152
                } while ($b > 0x80);
153
154
                if ($this->pool->maxAllowedPacket <= $len) {
155
                    // Too big packet
156
                    $this->finish();
157
                    return;
158
                }
159
160
                if ($buflen < $len + $i + 1) {
161
                    // not enough data yet
162
                    return;
163
                }
164
165
                $this->drain($i + 1);
166
                $this->onFrame($this->read($len), $frametype);
0 ignored issues
show
Security Bug introduced by
It seems like $this->read($len) targeting PHPDaemon\Network\IOStream::read() can also be of type false; however, PHPDaemon\Servers\WebSocket\Connection::onFrame() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
167
            } else {
168
                if (($p = $this->search("\xFF")) !== false) {
169
                    if ($this->pool->maxAllowedPacket <= $p - 1) {
170
                        // Too big packet
171
                        $this->finish();
172
                        return;
173
                    }
174
                    $this->drain(1);
175
                    $data = $this->read($p);
176
                    $this->drain(1);
177
                    $this->onFrame($data, 'STRING');
0 ignored issues
show
Security Bug introduced by
It seems like $data defined by $this->read($p) on line 175 can also be of type false; however, PHPDaemon\Servers\WebSocket\Connection::onFrame() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
178
                } else {
179
                    if ($this->pool->maxAllowedPacket < $buflen - 1) {
180
                        // Too big packet
181
                        $this->finish();
182
                        return;
183
                    }
184
                }
185
            }
186
        }
187
    }
188
}
189