Passed
Push — master ( edb799...f409da )
by Petr
07:56
created

AnswerMock::getResponseAuthDigest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 17
nc 1
nop 0
dl 0
loc 10
rs 9.7
c 1
b 0
f 0
1
<?php
2
3
namespace ProtocolsTests\Http;
4
5
6
use CommonTestClass;
7
use kalanis\RemoteRequest\Connection;
8
use kalanis\RemoteRequest\Protocols\Http;
9
use kalanis\RemoteRequest\Translations;
10
use kalanis\RemoteRequest\RequestException;
11
12
13
class AnswerMock extends Connection\Processor
14
{
15
    public function getResponseSimple()
16
    {
17
        return 'HTTP/0.1 900 KO' . Http::DELIMITER . Http::DELIMITER . 'abcdefghijkl';
18
    }
19
20
    public function getResponseEmpty()
21
    {
22
        return 'HTTP/0.1 901 KO';
23
    }
24
25
    public function getResponseHeaders()
26
    {
27
        return 'HTTP/0.1 902 KO' . Http::DELIMITER
28
            . 'Server: PhpUnit/9.3.0' . Http::DELIMITER
29
            . 'Content-Length: 12' . Http::DELIMITER
30
            . 'Content-Type: text/plain' . Http::DELIMITER
31
            . 'Connection: Closed' . Http::DELIMITER
32
            . Http::DELIMITER
33
            . 'abcdefghijkl'
34
        ;
35
    }
36
37
    public function getResponseChunked()
38
    {
39
        return 'HTTP/0.1 903 KO' . Http::DELIMITER
40
            . 'Server: PhpUnit/9.3.0' . Http::DELIMITER
41
            . 'Content-Length: 43' . Http::DELIMITER
42
            . 'Content-Type: text/html' . Http::DELIMITER
43
            . 'Transfer-Encoding: chunked' . Http::DELIMITER
44
            . 'Connection: Closed' . Http::DELIMITER
45
            . Http::DELIMITER
46
            . "4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n"
47
        ;
48
    }
49
50
    public function getResponseDeflated()
51
    {
52
        return 'HTTP/0.1 904 KO' . Http::DELIMITER
53
            . 'Server: PhpUnit/9.3.0' . Http::DELIMITER
54
            . 'Content-Length: 37' . Http::DELIMITER
55
            . 'Content-Type: text/plain' . Http::DELIMITER
56
            . 'Content-Encoding: deflate' . Http::DELIMITER
57
            . 'Connection: Closed' . Http::DELIMITER
58
            . Http::DELIMITER
59
            . base64_decode("S0xKTklNS8/IzMrOyc3LLygsKi4pLSuvqKwyMDQyMTUzt7AEAA==")
60
        ;
61
    }
62
63
    public function getResponseLargeHeader()
64
    {
65
        return 'HTTP/0.1 904 KO' . Http::DELIMITER
66
            . 'Server: PhpUnit/9.3.0' . Http::DELIMITER
67
            . 'Content-Length: 0' . Http::DELIMITER
68
            . 'Content-Type: text/plain' . Http::DELIMITER
69
            . 'Content-Encoding: deflate' . Http::DELIMITER
70
            . 'Server: PhpUnit/9.3.0' . Http::DELIMITER
71
            . 'Content-Length: 0' . Http::DELIMITER
72
            . 'Content-Type: text/plain' . Http::DELIMITER
73
            . 'Content-Encoding: deflate' . Http::DELIMITER
74
            . 'Connection: Closed'
75
        ;
76
    }
77
78
    /**
79
     * @return string
80
     * @link https://en.wikipedia.org/wiki/Digest_access_authentication
81
     */
82
    public function getResponseAuthDigest()
83
    {
84
        return 'HTTP/0.1 401 Unauthorized' . Http::DELIMITER
85
            . 'Server: PhpUnit/9.3.0' . Http::DELIMITER
86
            . 'Date: Sun, 10 Apr 2022 20:26:47 GMT' . Http::DELIMITER
87
            . 'WWW-Authenticate: Digest realm="[email protected]", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"' . Http::DELIMITER
88
            . 'Content-Type: text/html' . Http::DELIMITER
89
            . 'Content-Length: 153' . Http::DELIMITER
90
            . Http::DELIMITER
91
            . '<!DOCTYPE html>
92
<html>
93
  <head>
94
    <meta charset="UTF-8" />
95
    <title>Error</title>
96
  </head>
97
  <body>
98
    <h1>401 Unauthorized.</h1>
99
  </body>
100
</html>'
101
        ;
102
    }
103
}
104
105
106
class AnswerTest extends CommonTestClass
107
{
108
    /**
109
     * @throws RequestException
110
     */
111
    public function testSimple(): void
112
    {
113
        $method = new AnswerMock(new Translations());
114
        $lib = $this->prepareSimple($method->getResponseSimple());
115
        $this->assertEquals(900, $lib->getCode());
116
        $this->assertEquals('abcdefghijkl', $lib->getContent());
117
    }
118
119
    /**
120
     * @throws RequestException
121
     */
122
    public function testSimpleStream(): void
123
    {
124
        $method = new AnswerMock(new Translations());
125
        $lib = $this->prepareSimple(CommonTestClass::stringToResource($method->getResponseSimple()));
126
        $this->assertEquals(900, $lib->getCode());
127
        $this->assertEquals('abcdefghijkl', $lib->getContent());
128
    }
129
130
    /**
131
     * @throws RequestException
132
     */
133
    public function testEmpty(): void
134
    {
135
        $method = new AnswerMock(new Translations());
136
        $lib = $this->prepareSimple($method->getResponseEmpty());
137
        $this->assertEquals(901, $lib->getCode());
138
        $this->assertEquals('', $lib->getContent());
139
    }
140
141
    /**
142
     * @throws RequestException
143
     */
144
    public function testEmptyStream(): void
145
    {
146
        $method = new AnswerMock(new Translations());
147
        $lib = $this->prepareSimple(CommonTestClass::stringToResource($method->getResponseEmpty()));
148
        $this->assertEquals(901, $lib->getCode());
149
        $this->assertEquals('', $lib->getContent());
150
    }
151
152
    /**
153
     * @throws RequestException
154
     */
155
    public function testHeaders(): void
156
    {
157
        $method = new AnswerMock(new Translations());
158
        $lib = $this->prepareSimple($method->getResponseHeaders());
159
        $this->assertEquals(902, $lib->getCode());
160
        $this->assertEquals('abcdefghijkl', $lib->getContent());
161
        $this->assertEquals('text/plain', $lib->getHeader('Content-Type'));
162
        $this->assertEquals('Closed', $lib->getHeader('Connection'));
163
        $this->assertEquals('unknown', $lib->getHeader('what', 'unknown'));
164
165
        $this->assertNotEmpty($lib->getHeaders('Connection'));
166
        $this->assertEmpty($lib->getHeaders('unknown'));
167
        $this->assertArrayHasKey('Connection', $lib->getAllHeaders());
168
        $this->assertArrayNotHasKey('unknown', $lib->getAllHeaders());
169
        $this->assertFalse($lib->isSuccessful());
170
    }
171
172
    /**
173
     * @throws RequestException
174
     */
175
    public function testChunked(): void
176
    {
177
        $method = new AnswerMock(new Translations());
178
        $lib = $this->prepareSimple($method->getResponseChunked());
179
        $this->assertEquals(903, $lib->getCode());
180
        $this->assertEquals("Wikipedia in\r\n\r\nchunks.", $lib->getContent());
181
        $this->assertEquals('text/html', $lib->getHeader('Content-Type'));
182
        $this->assertEquals('chunked', $lib->getHeader('Transfer-Encoding'));
183
    }
184
185
    /**
186
     * @throws RequestException
187
     */
188
    public function testDeflated(): void
189
    {
190
        $method = new AnswerMock(new Translations());
191
        $lib = $this->prepareSimple($method->getResponseDeflated());
192
        $this->assertEquals(904, $lib->getCode());
193
        $this->assertEquals("abcdefghijklmnopqrstuvwxyz012456789", $lib->getContent());
194
        $this->assertEquals('text/plain', $lib->getHeader('Content-Type'));
195
        $this->assertEquals('deflate', $lib->getHeader('Content-Encoding'));
196
    }
197
198
    /**
199
     * @throws RequestException
200
     */
201
    public function testLargeHeader(): void
202
    {
203
        $method = new AnswerMock(new Translations());
204
        $this->expectException(RequestException::class);
205
        $this->prepareSimple(CommonTestClass::stringToResource($method->getResponseLargeHeader()));
206
    }
207
208
    /**
209
     * @throws RequestException
210
     */
211
    public function testAuthBasic(): void
212
    {
213
        $lang = new Translations();
214
        $method = new AnswerMock($lang);
215
        $lib = (new Http\Answer\AuthDigest($lang))->setResponse($method->getResponseAuthDigest());
216
        $lib->processContent();
217
        $this->assertEquals(401, $lib->getCode());
218
        $this->assertEquals('Digest', $lib->getAuthType());
219
        $this->assertEquals('[email protected]', $lib->getAuthRealm());
220
        $this->assertEquals(['auth', 'auth-int'], $lib->getQualitiesOfProtection());
221
        $this->assertEquals('dcd98b7102dd2f0e8b11d0f600bfb0c093', $lib->getRemoteRandomNumber());
222
        $this->assertEquals('5ccc069c403ebaf9f0171e9517f40e41', $lib->getDataToReturn());
223
        $this->assertEquals('md5', $lib->getAlgorithm());
224
    }
225
226
    /**
227
     * @throws RequestException
228
     */
229
    public function testAuthString(): void
230
    {
231
        $lang = new Translations();
232
        $method = new AnswerMock($lang);
233
        $lib = (new XAuthDigest($lang))->setResponse($method->getResponseAuthDigest());
234
        $lib->processContent();
235
        $this->assertEquals(401, $lib->getCode());
236
        $this->assertEquals('Digest', $lib->getAuthType());
237
        $this->assertEquals('[email protected]', $lib->getAuthRealm());
238
        $this->assertEquals(['auth', 'auth-int'], $lib->getQualitiesOfProtection());
239
        $this->assertEquals('dcd98b7102dd2f0e8b11d0f600bfb0c093', $lib->getRemoteRandomNumber());
240
        $this->assertEquals('5ccc069c403ebaf9f0171e9517f40e41', $lib->getDataToReturn());
241
        $this->assertEquals('md5', $lib->getAlgorithm());
242
    }
243
244
    /**
245
     * @throws RequestException
246
     */
247
    public function testAuthStream(): void
248
    {
249
        $lang = new Translations();
250
        $method = new AnswerMock($lang);
251
        $lib = (new XAuthDigest($lang))->setResponse(CommonTestClass::stringToResource($method->getResponseAuthDigest()));
252
        $lib->processContent();
253
        $this->assertEquals(401, $lib->getCode());
254
        $this->assertEquals('Digest', $lib->getAuthType());
255
        $this->assertEquals('[email protected]', $lib->getAuthRealm());
256
        $this->assertEquals(['auth', 'auth-int'], $lib->getQualitiesOfProtection());
257
        $this->assertEquals('dcd98b7102dd2f0e8b11d0f600bfb0c093', $lib->getRemoteRandomNumber());
258
        $this->assertEquals('5ccc069c403ebaf9f0171e9517f40e41', $lib->getDataToReturn());
259
        $this->assertEquals('md5', $lib->getAlgorithm());
260
    }
261
262
    /**
263
     * @param string|resource $content
264
     * @throws RequestException
265
     * @return Http\Answer
266
     */
267
    protected function prepareSimple($content): Http\Answer
268
    {
269
        $lib = new XAnswer(new Translations());
270
        $lib->addStringDecoding(new Http\Answer\DecodeStrings\Chunked());
271
        $lib->addStringDecoding(new Http\Answer\DecodeStrings\Deflated());
272
        return $lib->setResponse($content);
273
    }
274
}
275
276
277
class XAnswer extends Http\Answer
278
{
279
    protected $seekSize = 20; // in how big block we will look for delimiters
280
    protected $seekPos = 15; // must be reasonably lower than seekSize - because it's necessary to find delimiters even on edges
281
    protected $maxHeaderSize = 200; // die early in stream
282
    protected $maxStringSize = 100; // pass into stream
283
}
284
285
286
class XAuthDigest extends Http\Answer\AuthDigest
287
{
288
    protected $maxStringSize = 100; // pass into stream
289
}
290