1<?php
2
3require_once(__DIR__ . '/httpclient_mock.php');
4
5/**
6 * Tests are executed against an instance of go-httpbin
7 */
8class httpclient_http_test extends DokuWikiTest
9{
10    protected $server = 'http://httpbingo.org';
11
12    /**
13     * @group internet
14     */
15    public function test_simpleget()
16    {
17        $http = new HTTPMockClient();
18        $data = $http->get($this->server . '/get?foo=bar');
19        if ($http->noconnection()) {
20            $this->markTestSkipped('connection timed out');
21        }
22        $this->assertFalse($data === false, $http->errorInfo());
23        $resp = json_decode($data, true);
24        $this->assertTrue(is_array($resp), 'JSON response');
25        $this->assertArrayHasKey('args', $resp);
26        $this->assertEquals(['foo' => ['bar']], $resp['args']);
27    }
28
29    /**
30     * @group internet
31     */
32    public function test_dget()
33    {
34        $http = new HTTPMockClient();
35        $data = $http->dget($this->server . '/get', ['foo' => 'bar']);
36        if ($http->noconnection()) {
37            $this->markTestSkipped('connection timed out');
38        }
39        $this->assertFalse($data === false, $http->errorInfo());
40        $resp = json_decode($data, true);
41        $this->assertTrue(is_array($resp), 'JSON response');
42        $this->assertArrayHasKey('args', $resp);
43        $this->assertEquals(['foo' => ['bar']], $resp['args']);
44    }
45
46    /**
47     * @group internet
48     */
49    public function test_gzip()
50    {
51        $http = new HTTPMockClient();
52        $data = $http->get($this->server . '/gzip');
53        if ($http->noconnection()) {
54            $this->markTestSkipped('connection timed out');
55        }
56        $this->assertFalse($data === false, $http->errorInfo());
57        $resp = json_decode($data, true);
58        $this->assertTrue(is_array($resp), 'JSON response');
59        $this->assertArrayHasKey('gzipped', $resp);
60        $this->assertTrue($resp['gzipped']);
61    }
62
63    /**
64     * @group internet
65     */
66    public function test_simplepost()
67    {
68        $http = new HTTPMockClient();
69        $data = $http->post($this->server . '/post', ['foo' => 'bar']);
70        if ($http->noconnection()) {
71            $this->markTestSkipped('connection timed out');
72        }
73        $this->assertFalse($data === false, $http->errorInfo());
74        $resp = json_decode($data, true);
75        $this->assertTrue(is_array($resp), 'JSON response');
76        $this->assertArrayHasKey('form', $resp);
77        $this->assertEquals(['foo' => ['bar']], $resp['form']);
78    }
79
80    /**
81     * @group internet
82     */
83    public function test_redirect()
84    {
85        $http = new HTTPMockClient();
86        $data = $http->get($this->server . '/redirect/3');
87        if ($http->noconnection()) {
88            $this->markTestSkipped('connection timed out');
89        }
90        $this->assertFalse($data === false, $http->errorInfo());
91        $resp = json_decode($data, true);
92        $this->assertTrue(is_array($resp), 'JSON response');
93        $this->assertArrayHasKey('url', $resp);
94        $this->assertMatchesRegularExpression('/\/get$/', $resp['url']);
95    }
96
97    /**
98     * @group internet
99     */
100    public function test_relredirect()
101    {
102        $http = new HTTPMockClient();
103        $data = $http->get($this->server . '/relative-redirect/3');
104        if ($http->noconnection()) {
105            $this->markTestSkipped('connection timed out');
106        }
107        $this->assertFalse($data === false, $http->errorInfo());
108        $resp = json_decode($data, true);
109        $this->assertTrue(is_array($resp), 'JSON response');
110        $this->assertArrayHasKey('url', $resp);
111        $this->assertMatchesRegularExpression('/\/get$/', $resp['url']);
112    }
113
114    /**
115     * @group internet
116     */
117    public function test_redirectfail()
118    {
119        $http = new HTTPMockClient();
120        $data = $http->get($this->server . '/redirect/5');
121        if ($http->noconnection()) {
122            $this->markTestSkipped('connection timed out');
123        }
124        $this->assertTrue($data === false, $http->errorInfo());
125        $this->assertEquals('Maximum number of redirects exceeded', $http->error);
126    }
127
128    /**
129     * @group internet
130     */
131    public function test_cookies()
132    {
133        $http = new HTTPMockClient();
134        $http->get($this->server . '/cookies/set?foo=bar');
135        if ($http->noconnection()) {
136            $this->markTestSkipped('connection timed out');
137        }
138        $this->assertEquals(['foo' => 'bar'], $http->cookies);
139        $data = $http->get($this->server . '/cookies');
140        if ($http->noconnection()) {
141            $this->markTestSkipped('connection timed out');
142        }
143        $this->assertFalse($data === false, $http->errorInfo());
144        $resp = json_decode($data, true);
145        $this->assertTrue(is_array($resp), 'JSON response');
146        $this->assertEquals(['foo' => 'bar'], $resp);
147    }
148
149    /**
150     * @group internet
151     */
152    public function test_teapot()
153    {
154        $http = new HTTPMockClient();
155        $data = $http->get($this->server . '/status/418');
156        if ($http->noconnection()) {
157            $this->markTestSkipped('connection timed out');
158        }
159        $this->assertTrue($data === false, $http->errorInfo());
160        $this->assertEquals(418, $http->status);
161    }
162
163    /**
164     * @group internet
165     */
166    public function test_maxbody()
167    {
168        $http = new HTTPMockClient();
169        $http->max_bodysize = 250;
170
171        // this should abort completely
172        $data = $http->get($this->server . '/stream/30');
173        if ($http->noconnection()) {
174            $this->markTestSkipped('connection timed out');
175        }
176        $this->assertTrue($data === false, $http->errorInfo());
177
178        // this should read just the needed bytes
179        $http->max_bodysize_abort = false;
180        $http->keep_alive = false;
181        $data = $http->get($this->server . '/stream/30');
182        if ($http->noconnection()) {
183            $this->markTestSkipped('connection timed out');
184        }
185        $this->assertFalse($data === false, $http->errorInfo());
186        /* should read no more than max_bodysize+1 */
187        $this->assertLessThanOrEqual(251, strlen($data));
188    }
189
190    /**
191     * @group internet
192     */
193    public function test_maxbodyok()
194    {
195        $http = new HTTPMockClient();
196        $http->max_bodysize = 500 * 1024;
197        $data = $http->get($this->server . '/stream/5');
198        if ($http->noconnection()) {
199            $this->markTestSkipped('connection timed out');
200        }
201        $this->assertTrue($data !== false, $http->errorInfo());
202        $http->max_bodysize_abort = false;
203        $data = $http->get($this->server . '/stream/5');
204        if ($http->noconnection()) {
205            $this->markTestSkipped('connection timed out');
206        }
207        $this->assertTrue($data !== false, $http->errorInfo());
208    }
209
210    /**
211     * @group internet
212     */
213    function test_basicauth()
214    {
215        $http = new HTTPMockClient();
216        $http->user = 'user';
217        $http->pass = 'pass';
218        $data = $http->get($this->server . '/basic-auth/user/pass');
219        if ($http->noconnection()) {
220            $this->markTestSkipped('connection timed out');
221        }
222        $this->assertFalse($data === false, $http->errorInfo());
223        $resp = json_decode($data, true);
224        $this->assertTrue(is_array($resp), 'JSON response');
225        $this->assertEquals(['authorized' => true, 'user' => 'user'], $resp);
226    }
227
228    /**
229     * @group internet
230     */
231    public function test_basicauthfail()
232    {
233        $http = new HTTPMockClient();
234        $http->user = 'user';
235        $http->pass = 'invalid';
236        $data = $http->get($this->server . '/basic-auth/user/pass');
237        if ($http->noconnection()) {
238            $this->markTestSkipped('connection timed out');
239        }
240        $this->assertTrue($data === false, $http->errorInfo());
241        $this->assertEquals(401, $http->status);
242    }
243
244    /**
245     * @group internet
246     */
247    public function test_timeout()
248    {
249        $http = new HTTPMockClient();
250        $http->timeout = 5;
251        $data = $http->get($this->server . '/delay/10');
252        $this->assertTrue($data === false, $http->errorInfo());
253        $this->assertEquals(-100, $http->status);
254    }
255
256    /**
257     * @group internet
258     */
259    public function test_headers()
260    {
261        $http = new HTTPMockClient();
262        $data = $http->get($this->server . '/response-headers?baz=&foo=bar');
263        if ($http->noconnection()) {
264            $this->markTestSkipped('connection timed out');
265        }
266        $this->assertFalse($data === false, $http->errorInfo());
267        $resp = json_decode($data, true);
268        $this->assertTrue(is_array($resp), 'JSON response');
269        $this->assertArrayHasKey('baz', $http->resp_headers);
270        $this->assertArrayHasKey('foo', $http->resp_headers);
271        $this->assertEquals('bar', $http->resp_headers['foo']);
272    }
273
274    /**
275     * @group internet
276     */
277    public function test_chunked()
278    {
279        $http = new HTTPMockClient();
280        $data = $http->get($this->server . '/stream-bytes/5000?chunk_size=250');
281        if ($http->noconnection()) {
282            $this->markTestSkipped('connection timed out');
283        }
284        $this->assertFalse($data === false, $http->errorInfo());
285        $this->assertEquals(5000, strlen($data));
286    }
287
288    /**
289     * This address caused trouble with stream_select()
290     *
291     * @group internet
292     * @group flaky
293     */
294    public function test_wikimatrix()
295    {
296        $http = new HTTPMockClient();
297        $data = $http->get('http://www.wikimatrix.org/cfeed/dokuwiki/-/-');
298        if ($http->noconnection()) {
299            $this->markTestSkipped('connection timed out');
300        }
301        $this->assertTrue($data !== false, $http->errorInfo());
302    }
303
304    /**
305     * @throws ReflectionException
306     */
307    public function test_postencode()
308    {
309        $http = new HTTPMockClient();
310
311        // check simple data
312        $data = [
313            'öä?' => 'öä?',
314            'foo' => 'bang',
315        ];
316        $this->assertEquals(
317            '%C3%B6%C3%A4%3F=%C3%B6%C3%A4%3F&foo=bang',
318            $this->callInaccessibleMethod($http, 'postEncode', [$data]),
319            'simple'
320        );
321
322        // check first level numeric array
323        $data = [
324            'foo' => 'bang',
325            'ärr' => ['ö', 'b', 'c'],
326        ];
327        $this->assertEquals(
328            'foo=bang&%C3%A4rr%5B0%5D=%C3%B6&%C3%A4rr%5B1%5D=b&%C3%A4rr%5B2%5D=c',
329            $this->callInaccessibleMethod($http, 'postEncode', [$data]),
330            'onelevelnum'
331        );
332
333        // check first level associative array
334        $data = [
335            'foo' => 'bang',
336            'ärr' => ['ö' => 'ä', 'b' => 'c'],
337        ];
338        $this->assertEquals(
339            'foo=bang&%C3%A4rr%5B%C3%B6%5D=%C3%A4&%C3%A4rr%5Bb%5D=c',
340            $this->callInaccessibleMethod($http, 'postEncode', [$data]),
341            'onelevelassoc'
342        );
343
344        // check first level associative array
345        $data = [
346            'foo' => 'bang',
347            'ärr' => ['ö' => 'ä', 'ä' => ['ö' => 'ä']],
348        ];
349        $this->assertEquals(
350            'foo=bang&%C3%A4rr%5B%C3%B6%5D=%C3%A4&%C3%A4rr%5B%C3%A4%5D%5B%C3%B6%5D=%C3%A4',
351            $this->callInaccessibleMethod($http, 'postEncode', [$data]),
352            'twolevelassoc'
353        );
354    }
355}
356