Completed
Push — master ( c55d2b...07e932 )
by Vasily
03:55
created

VE   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 169
Duplicated Lines 59.76 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 27
c 1
b 0
f 0
lcom 1
cbo 2
dl 101
loc 169
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A sendHandshakeReply() 0 20 4
B _computeKey() 24 24 5
C sendFrame() 26 42 8
C onRead() 51 53 10

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
	const STRING = 0x00;
14
	const BINARY = 0x80;
15
16
	/**
17
	 * Sends a handshake message reply
18
	 * @param string Received data (no use in this class)
19
	 * @return boolean OK?
20
	 */
21
	public function sendHandshakeReply($extraHeaders = '') {
22
		if (!isset($this->server['HTTP_SEC_WEBSOCKET_ORIGIN'])) {
23
			$this->server['HTTP_SEC_WEBSOCKET_ORIGIN'] = '';
24
		}
25
26
		$this->write("HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
27
				. "Upgrade: WebSocket\r\n"
28
				. "Connection: Upgrade\r\n"
29
				. "Sec-WebSocket-Origin: " . $this->server['HTTP_ORIGIN'] . "\r\n"
30
				. "Sec-WebSocket-Location: ws://" . $this->server['HTTP_HOST'] . $this->server['REQUEST_URI'] . "\r\n"
31
		);
32
		if ($this->pool->config->expose->value) {
33
			$this->writeln('X-Powered-By: phpDaemon/' . Daemon::$version);
34
		}
35
		if (isset($this->server['HTTP_SEC_WEBSOCKET_PROTOCOL'])) {
36
			$this->writeln("Sec-WebSocket-Protocol: " . $this->server['HTTP_SEC_WEBSOCKET_PROTOCOL']);
37
		}
38
		$this->writeln($extraHeaders);
39
		return true;
40
	}
41
42
	/**
43
	 * Computes key for Sec-WebSocket.
44
	 * @param string Key
45
	 * @return string Result
46
	 */
47 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...
48
		$spaces = 0;
49
		$digits = '';
50
51
		for ($i = 0, $s = strlen($key); $i < $s; ++$i) {
52
			$c = binarySubstr($key, $i, 1);
53
54
			if ($c === "\x20") {
55
				++$spaces;
56
			}
57
			elseif (ctype_digit($c)) {
58
				$digits .= $c;
59
			}
60
		}
61
62
		if ($spaces > 0) {
63
			$result = (float)floor($digits / $spaces);
64
		}
65
		else {
66
			$result = (float)$digits;
67
		}
68
69
		return pack('N', $result);
70
	}
71
72
	/**
73
	 * Sends a frame.
74
	 * @param  string   $data  Frame's data.
75
	 * @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...
76
	 * @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...
77
	 * @callback $cb ( )
78
	 * @return boolean         Success.
79
	 */
80
	public function sendFrame($data, $type = null, $cb = null) {
81
		if (!$this->handshaked) {
82
			return false;
83
		}
84
85
		if ($this->finished && $type !== 'CONNCLOSE') {
86
			return false;
87
		}
88
89
		// Binary
90
		$type = $this->getFrameType($type);
91 View Code Duplication
		if (($type & self::BINARY) === self::BINARY) {
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...
92
			$n   = strlen($data);
93
			$len = '';
94
			$pos = 0;
95
96
			char:
97
98
			++$pos;
99
			$c = $n >> 0 & 0x7F;
100
			$n >>= 7;
101
102
			if ($pos !== 1) {
103
				$c += 0x80;
104
			}
105
106
			if ($c !== 0x80) {
107
				$len = chr($c) . $len;
108
				goto char;
109
			};
110
111
			$this->write(chr(self::BINARY) . $len . $data);
112
		}
113
		// String
114
		else {
115
			$this->write(chr(self::STRING) . $data . "\xFF");
116
		}
117
		if ($cb !== null) {
118
			$this->onWriteOnce($cb);
119
		}
120
		return true;
121
	}
122
123
	/**
124
	 * Called when new data received
125
	 * @return void
126
	 */
127
	public function onRead() {
128 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...
129
			$hdr       = $this->look(10);
130
			$frametype = ord(binarySubstr($hdr, 0, 1));
131
			if (($frametype & 0x80) === 0x80) {
132
				$len = 0;
133
				$i   = 0;
134
				do {
135
					if ($buflen < $i + 1) {
136
						return;
137
					}
138
					$b = ord(binarySubstr($hdr, ++$i, 1));
139
					$n = $b & 0x7F;
140
					$len *= 0x80;
141
					$len += $n;
142
				} while ($b > 0x80);
143
144
				if ($this->pool->maxAllowedPacket <= $len) {
145
					// Too big packet
146
					$this->finish();
147
					return;
148
				}
149
150
				if ($buflen < $len + $i + 1) {
151
					// not enough data yet
152
					return;
153
				}
154
155
				$this->drain($i + 1);
156
				$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...
157
			}
158
			else {
159
				if (($p = $this->search("\xFF")) !== false) {
160
					if ($this->pool->maxAllowedPacket <= $p - 1) {
161
						// Too big packet
162
						$this->finish();
163
						return;
164
					}
165
					$this->drain(1);
166
					$data = $this->read($p);
167
					$this->drain(1);
168
					$this->onFrame($data, 'STRING');
0 ignored issues
show
Security Bug introduced by
It seems like $data defined by $this->read($p) on line 166 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...
169
				}
170
				else {
171
					if ($this->pool->maxAllowedPacket < $buflen - 1) {
172
						// Too big packet
173
						$this->finish();
174
						return;
175
					}
176
				}
177
			}
178
		}
179
	}
180
}
181