Completed
Pull Request — master (#100)
by Maxime
02:23
created

Response::create()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 14
cts 14
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 15
nc 7
nop 1
crap 5
1
<?php
2
/**
3
 * This file is a part of a nekland library
4
 *
5
 * (c) Nekland <[email protected]>
6
 *
7
 * For the full license, take a look to the LICENSE file
8
 * on the root directory of this project
9
 */
10
11
namespace Nekland\Woketo\Http;
12
13
14
use Nekland\Woketo\Exception\Http\HttpException;
15
use Nekland\Woketo\Exception\Http\IncompleteHttpMessageException;
16
use React\Socket\ConnectionInterface;
17
18
class Response extends AbstractHttpMessage
19
{
20
    const SWITCHING_PROTOCOLS = '101 Switching Protocols';
21
    const BAD_REQUEST = '400 Bad Request';
22
23
    /**
24
     * @var string For example "404 Not Found"
25
     */
26
    private $httpResponse;
27
28
    /**
29
     * @var int
30
     */
31
    private $statusCode;
32
33
    /**
34
     * @var string
35
     */
36
    private $reason;
37
38 13
    public function __construct()
39
    {
40 13
        $this->setHttpVersion('HTTP/1.1');
41 13
    }
42
43
    /**
44
     * @param string $httpResponse
45
     * @return Response
46
     */
47 7
    public function setHttpResponse($httpResponse)
48
    {
49 7
        $this->httpResponse = $httpResponse;
50
51 7
        return $this;
52
    }
53
54
    /**
55
     * @return int
56
     */
57 2
    public function getStatusCode(): int
58
    {
59 2
        return $this->statusCode;
60
    }
61
62
    /**
63
     * @param int $statusCode
64
     */
65 5
    public function setStatusCode(int $statusCode)
66
    {
67 5
        $this->statusCode = $statusCode;
68 5
    }
69
70
    /**
71
     * @return string
72
     */
73 2
    public function getReason(): string
74
    {
75 2
        return $this->reason;
76
    }
77
78
    /**
79
     * @param string $reason
80
     */
81 5
    public function setReason(string $reason)
82
    {
83 5
        $this->reason = $reason;
84 5
    }
85
86
    /**
87
     * @return string
88
     */
89 2
    public function getAcceptKey()
90
    {
91 2
        return $this->getHeader('Sec-WebSocket-Accept');
92
    }
93
94
    /**
95
     * @param ConnectionInterface $stream
96
     */
97 7
    public function send(ConnectionInterface $stream)
98
    {
99 7
        $stringResponse = $this->getHttpVersion() . ' ' . $this->httpResponse . "\r\n";
100
101 7
        foreach ($this->getHeaders() as $name => $content) {
102 7
            $stringResponse .= $name . ': '. $content . "\r\n";
103
        }
104
105
        // No content to concatenate
106 7
        $stringResponse .= "\r\n";
107
108 7
        $stream->write($stringResponse);
109 7
    }
110
111 6
    public static function createSwitchProtocolResponse()
112
    {
113 6
        $response = new Response();
114
115 6
        $response->setHttpResponse(Response::SWITCHING_PROTOCOLS);
116 6
        $response->addHeader('Upgrade', 'websocket');
117 6
        $response->addHeader('Connection', 'Upgrade');
118
119 6
        return $response;
120
    }
121
122
    /**
123
     * @param string $data
124
     * @return Response
125
     * @throws HttpException
126
     */
127 6
    public static function create(string &$data) : Response
128
    {
129 6
        if (!\preg_match('/\\r\\n\\r\\n/', $data)) {
130
            throw new IncompleteHttpMessageException();
131
        }
132
133 6
        $responseString = '';
0 ignored issues
show
Unused Code introduced by
$responseString is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
134 6
        if (!\preg_match('/\\r\\n\\r\\n$/', $data)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
135
136
        }
137
138 6
        $response = new Response();
139
140 6
        $lines = \explode("\r\n", $data);
141 6
        Response::initResponse($lines[0], $response);
142
143 5
        unset($lines[0]);
144 5
        Response::initHeaders($lines, $response);
145
146 5
        if ($response->getHeader('Upgrade') !== 'websocket') {
147 1
            throw new HttpException('Missing or wrong upgrade header.');
148
        }
149 4
        if ($response->getHeader('Connection') !== 'Upgrade') {
150 1
            throw new HttpException('Missing upgrade header.');
151
        }
152
153 3
        return $response;
154
    }
155
156
    /**
157
     * @param string   $firstLine
158
     * @param Response $response
159
     * @throws HttpException
160
     */
161 6
    protected static function initResponse(string $firstLine, Response $response)
162
    {
163 6
        $httpElements = \explode(' ', $firstLine);
164
165 6
        if (!\preg_match('/HTTP\/[1-2\.]+/',$httpElements[0])) {
166
            throw Response::createNotHttpException($firstLine);
167
        }
168 6
        $response->setHttpVersion($httpElements[0]);
169 6
        unset($httpElements[0]);
170
171 6
        if ($httpElements[1] != 101) {
172 1
            throw new HttpException(
173 1
                sprintf('Attempted 101 response but got %s', $httpElements[1])
174
            );
175
        }
176 5
        $response->setStatusCode($httpElements[1]);
177 5
        unset($httpElements[1]);
178
179 5
        $response->setReason(implode(' ', $httpElements));
180 5
    }
181
}
182