ResponseStream::isReadable()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
ccs 1
cts 1
cp 1
rs 10
c 1
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Http\Adapter\Artax\Internal;
4
5
use Amp\Artax;
6
use Amp\ByteStream\InputStream;
7
use Amp\ByteStream\IteratorStream;
8
use Amp\CancellationTokenSource;
9
use Amp\CancelledException;
10
use Amp\Emitter;
11
use Amp\Promise;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Http\Adapter\Artax\Internal\Promise.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
use Psr\Http\Message\StreamInterface;
13
14
/**
15
 * PSR-7 stream implementation that converts an `Amp\ByteStream\InputStream` into a PSR-7 compatible stream.
16
 *
17
 * @internal
18
 */
19
class ResponseStream implements StreamInterface
20
{
21
    private $buffer = '';
22
23
    private $position = 0;
24
25
    private $eof = false;
26
27
    private $body;
28
29
    private $cancellationTokenSource;
30
31
    /**
32 60
     * @param InputStream             $body                    HTTP response stream to wrap.
33
     * @param CancellationTokenSource $cancellationTokenSource Cancellation source bound to the request to abort it.
34 60
     */
35 60
    public function __construct(InputStream $body, CancellationTokenSource $cancellationTokenSource)
36 60
    {
37
        $this->body = $body;
38 2
        $this->cancellationTokenSource = $cancellationTokenSource;
39
    }
40
41 2
    public function __toString()
42 1
    {
43 1
        try {
44
            return $this->getContents();
45
        } catch (\Throwable $e) {
46
            return '';
47 60
        }
48
    }
49 60
50 60
    public function __destruct()
51
    {
52 60
        $this->close();
53
    }
54 60
55
    public function close()
56 60
    {
57 60
        $this->cancellationTokenSource->cancel();
58 60
59 60
        $emitter = new Emitter();
60
        $emitter->fail(new Artax\HttpException('The stream has been closed'));
61 1
        $this->body = new IteratorStream($emitter->iterate());
62
    }
63 1
64 1
    public function detach()
65
    {
66 1
        $this->close();
67
    }
68 1
69
    public function getSize()
70
    {
71 1
        return null;
72
    }
73 1
74
    public function tell()
75
    {
76 52
        return $this->position;
77
    }
78 52
79
    public function eof()
80
    {
81 1
        return $this->eof;
82
    }
83 1
84
    public function isSeekable()
85
    {
86 2
        return false;
87
    }
88 2
89
    public function seek($offset, $whence = SEEK_SET)
90
    {
91 1
        throw new \RuntimeException('Stream is not seekable');
92
    }
93 1
94
    public function rewind()
95
    {
96 1
        $this->seek(0);
97
    }
98 1
99
    public function isWritable()
100
    {
101 1
        return false;
102
    }
103 1
104
    public function write($string)
105
    {
106 1
        throw new \RuntimeException('Stream is not writable');
107
    }
108 1
109
    public function isReadable()
110
    {
111 55
        return true;
112
    }
113 55
114 1
    public function read($length)
115
    {
116
        if ($this->eof) {
117 55
            return '';
118
        }
119 55
120 4
        if ('' === $this->buffer) {
121 3
            try {
122 1
                $this->buffer = Promise\wait($this->body->read());
123 1
            } catch (Artax\HttpException $e) {
124
                throw new \RuntimeException('Reading from the stream failed', 0, $e);
125
            } catch (CancelledException $e) {
126 51
                throw new \RuntimeException('Reading from the stream failed', 0, $e);
127 51
            }
128
129 51
            if (null === $this->buffer) {
130
                $this->eof = true;
131
132
                return '';
133 47
            }
134 47
        }
135 47
136
        $read = \substr($this->buffer, 0, $length);
137 47
        $this->buffer = (string) \substr($this->buffer, $length);
138
        $this->position += \strlen($read);
139
140 52
        return $read;
141
    }
142 52
143
    public function getContents()
144 52
    {
145 52
        $buffer = '';
146
147
        while (!$this->eof()) {
148 51
            $buffer .= $this->read(8192 * 8);
149
        }
150
151 1
        return $buffer;
152
    }
153 1
154
    public function getMetadata($key = null)
155
    {
156
        return null === $key ? [] : null;
157
    }
158
}
159