GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 5cefd1...492078 )
by Anton
04:08
created

Request::handleData()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 18
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 30
rs 9.3554
1
<?php
2
3
namespace React\Http\Client;
4
5
use Evenement\EventEmitter;
6
use React\Promise;
7
use React\Socket\ConnectionInterface;
8
use React\Socket\ConnectorInterface;
9
use React\Stream\WritableStreamInterface;
10
use RingCentral\Psr7 as gPsr;
11
12
/**
13
 * @event response
14
 * @event drain
15
 * @event error
16
 * @event end
17
 * @internal
18
 */
19
class Request extends EventEmitter implements WritableStreamInterface
20
{
21
    const STATE_INIT = 0;
22
    const STATE_WRITING_HEAD = 1;
23
    const STATE_HEAD_WRITTEN = 2;
24
    const STATE_END = 3;
25
26
    private $connector;
27
    private $requestData;
28
29
    private $stream;
30
    private $buffer;
31
    private $responseFactory;
0 ignored issues
show
introduced by
The private property $responseFactory is not used, and could be removed.
Loading history...
32
    private $state = self::STATE_INIT;
33
    private $ended = false;
34
35
    private $pendingWrites = '';
36
37
    public function __construct(ConnectorInterface $connector, RequestData $requestData)
38
    {
39
        $this->connector = $connector;
40
        $this->requestData = $requestData;
41
    }
42
43
    public function isWritable()
44
    {
45
        return self::STATE_END > $this->state && !$this->ended;
46
    }
47
48
    private function writeHead()
49
    {
50
        $this->state = self::STATE_WRITING_HEAD;
51
52
        $requestData = $this->requestData;
53
        $streamRef = &$this->stream;
54
        $stateRef = &$this->state;
55
        $pendingWrites = &$this->pendingWrites;
56
        $that = $this;
57
58
        $promise = $this->connect();
59
        $promise->then(
60
            function (ConnectionInterface $stream) use ($requestData, &$streamRef, &$stateRef, &$pendingWrites, $that) {
61
                $streamRef = $stream;
62
63
                $stream->on('drain', array($that, 'handleDrain'));
64
                $stream->on('data', array($that, 'handleData'));
65
                $stream->on('end', array($that, 'handleEnd'));
66
                $stream->on('error', array($that, 'handleError'));
67
                $stream->on('close', array($that, 'handleClose'));
68
69
                $headers = (string) $requestData;
70
71
                $more = $stream->write($headers . $pendingWrites);
72
73
                $stateRef = Request::STATE_HEAD_WRITTEN;
74
75
                // clear pending writes if non-empty
76
                if ($pendingWrites !== '') {
77
                    $pendingWrites = '';
78
79
                    if ($more) {
80
                        $that->emit('drain');
81
                    }
82
                }
83
            },
84
            array($this, 'closeError')
85
        );
86
87
        $this->on('close', function() use ($promise) {
88
            $promise->cancel();
0 ignored issues
show
Bug introduced by
The method cancel() does not exist on React\Promise\PromiseInterface. It seems like you code against a sub-type of said class. However, the method does not exist in React\Promise\ExtendedPromiseInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

88
            $promise->/** @scrutinizer ignore-call */ 
89
                      cancel();
Loading history...
89
        });
90
    }
91
92
    public function write($data)
93
    {
94
        if (!$this->isWritable()) {
95
            return false;
96
        }
97
98
        // write directly to connection stream if already available
99
        if (self::STATE_HEAD_WRITTEN <= $this->state) {
100
            return $this->stream->write($data);
101
        }
102
103
        // otherwise buffer and try to establish connection
104
        $this->pendingWrites .= $data;
105
        if (self::STATE_WRITING_HEAD > $this->state) {
106
            $this->writeHead();
107
        }
108
109
        return false;
110
    }
111
112
    public function end($data = null)
113
    {
114
        if (!$this->isWritable()) {
115
            return;
116
        }
117
118
        if (null !== $data) {
119
            $this->write($data);
120
        } else if (self::STATE_WRITING_HEAD > $this->state) {
121
            $this->writeHead();
122
        }
123
124
        $this->ended = true;
125
    }
126
127
    /** @internal */
128
    public function handleDrain()
129
    {
130
        $this->emit('drain');
131
    }
132
133
    /** @internal */
134
    public function handleData($data)
135
    {
136
        $this->buffer .= $data;
137
138
        // buffer until double CRLF (or double LF for compatibility with legacy servers)
139
        if (false !== strpos($this->buffer, "\r\n\r\n") || false !== strpos($this->buffer, "\n\n")) {
140
            try {
141
                $response = gPsr\parse_response($this->buffer);
0 ignored issues
show
Bug introduced by
The function parse_response was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

141
                $response = /** @scrutinizer ignore-call */ gPsr\parse_response($this->buffer);
Loading history...
142
                $bodyChunk = (string) $response->getBody();
143
            } catch (\InvalidArgumentException $exception) {
144
                $this->emit('error', array($exception));
145
            }
146
147
            $this->buffer = null;
148
149
            $this->stream->removeListener('drain', array($this, 'handleDrain'));
150
            $this->stream->removeListener('data', array($this, 'handleData'));
151
            $this->stream->removeListener('end', array($this, 'handleEnd'));
152
            $this->stream->removeListener('error', array($this, 'handleError'));
153
            $this->stream->removeListener('close', array($this, 'handleClose'));
154
155
            if (!isset($response)) {
156
                return;
157
            }
158
159
            $this->stream->on('close', array($this, 'handleClose'));
160
161
            $this->emit('response', array($response, $this->stream));
162
163
            $this->stream->emit('data', array($bodyChunk));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $bodyChunk does not seem to be defined for all execution paths leading up to this point.
Loading history...
164
        }
165
    }
166
167
    /** @internal */
168
    public function handleEnd()
169
    {
170
        $this->closeError(new \RuntimeException(
171
            "Connection ended before receiving response"
172
        ));
173
    }
174
175
    /** @internal */
176
    public function handleError(\Exception $error)
177
    {
178
        $this->closeError(new \RuntimeException(
179
            "An error occurred in the underlying stream",
180
            0,
181
            $error
182
        ));
183
    }
184
185
    /** @internal */
186
    public function handleClose()
187
    {
188
        $this->close();
189
    }
190
191
    /** @internal */
192
    public function closeError(\Exception $error)
193
    {
194
        if (self::STATE_END <= $this->state) {
195
            return;
196
        }
197
        $this->emit('error', array($error));
198
        $this->close();
199
    }
200
201
    public function close()
202
    {
203
        if (self::STATE_END <= $this->state) {
204
            return;
205
        }
206
207
        $this->state = self::STATE_END;
208
        $this->pendingWrites = '';
209
210
        if ($this->stream) {
211
            $this->stream->close();
212
        }
213
214
        $this->emit('close');
215
        $this->removeAllListeners();
216
    }
217
218
    protected function connect()
219
    {
220
        $scheme = $this->requestData->getScheme();
221
        if ($scheme !== 'https' && $scheme !== 'http') {
222
            return Promise\reject(
0 ignored issues
show
Bug introduced by
The function reject was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

222
            return /** @scrutinizer ignore-call */ Promise\reject(
Loading history...
223
                new \InvalidArgumentException('Invalid request URL given')
224
            );
225
        }
226
227
        $host = $this->requestData->getHost();
228
        $port = $this->requestData->getPort();
229
230
        if ($scheme === 'https') {
231
            $host = 'tls://' . $host;
232
        }
233
234
        return $this->connector
235
            ->connect($host . ':' . $port);
236
    }
237
}
238