Yaffs site version 1.1
[yaffs-website] / vendor / symfony / http-foundation / Tests / RequestTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpFoundation\Tests;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
16 use Symfony\Component\HttpFoundation\Session\Session;
17 use Symfony\Component\HttpFoundation\Request;
18
19 class RequestTest extends TestCase
20 {
21     public function testInitialize()
22     {
23         $request = new Request();
24
25         $request->initialize(array('foo' => 'bar'));
26         $this->assertEquals('bar', $request->query->get('foo'), '->initialize() takes an array of query parameters as its first argument');
27
28         $request->initialize(array(), array('foo' => 'bar'));
29         $this->assertEquals('bar', $request->request->get('foo'), '->initialize() takes an array of request parameters as its second argument');
30
31         $request->initialize(array(), array(), array('foo' => 'bar'));
32         $this->assertEquals('bar', $request->attributes->get('foo'), '->initialize() takes an array of attributes as its third argument');
33
34         $request->initialize(array(), array(), array(), array(), array(), array('HTTP_FOO' => 'bar'));
35         $this->assertEquals('bar', $request->headers->get('FOO'), '->initialize() takes an array of HTTP headers as its sixth argument');
36     }
37
38     public function testGetLocale()
39     {
40         $request = new Request();
41         $request->setLocale('pl');
42         $locale = $request->getLocale();
43         $this->assertEquals('pl', $locale);
44     }
45
46     public function testGetUser()
47     {
48         $request = Request::create('http://user_test:password_test@test.com/');
49         $user = $request->getUser();
50
51         $this->assertEquals('user_test', $user);
52     }
53
54     public function testGetPassword()
55     {
56         $request = Request::create('http://user_test:password_test@test.com/');
57         $password = $request->getPassword();
58
59         $this->assertEquals('password_test', $password);
60     }
61
62     public function testIsNoCache()
63     {
64         $request = new Request();
65         $isNoCache = $request->isNoCache();
66
67         $this->assertFalse($isNoCache);
68     }
69
70     public function testGetContentType()
71     {
72         $request = new Request();
73         $contentType = $request->getContentType();
74
75         $this->assertNull($contentType);
76     }
77
78     public function testSetDefaultLocale()
79     {
80         $request = new Request();
81         $request->setDefaultLocale('pl');
82         $locale = $request->getLocale();
83
84         $this->assertEquals('pl', $locale);
85     }
86
87     public function testCreate()
88     {
89         $request = Request::create('http://test.com/foo?bar=baz');
90         $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri());
91         $this->assertEquals('/foo', $request->getPathInfo());
92         $this->assertEquals('bar=baz', $request->getQueryString());
93         $this->assertEquals(80, $request->getPort());
94         $this->assertEquals('test.com', $request->getHttpHost());
95         $this->assertFalse($request->isSecure());
96
97         $request = Request::create('http://test.com/foo', 'GET', array('bar' => 'baz'));
98         $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri());
99         $this->assertEquals('/foo', $request->getPathInfo());
100         $this->assertEquals('bar=baz', $request->getQueryString());
101         $this->assertEquals(80, $request->getPort());
102         $this->assertEquals('test.com', $request->getHttpHost());
103         $this->assertFalse($request->isSecure());
104
105         $request = Request::create('http://test.com/foo?bar=foo', 'GET', array('bar' => 'baz'));
106         $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri());
107         $this->assertEquals('/foo', $request->getPathInfo());
108         $this->assertEquals('bar=baz', $request->getQueryString());
109         $this->assertEquals(80, $request->getPort());
110         $this->assertEquals('test.com', $request->getHttpHost());
111         $this->assertFalse($request->isSecure());
112
113         $request = Request::create('https://test.com/foo?bar=baz');
114         $this->assertEquals('https://test.com/foo?bar=baz', $request->getUri());
115         $this->assertEquals('/foo', $request->getPathInfo());
116         $this->assertEquals('bar=baz', $request->getQueryString());
117         $this->assertEquals(443, $request->getPort());
118         $this->assertEquals('test.com', $request->getHttpHost());
119         $this->assertTrue($request->isSecure());
120
121         $request = Request::create('test.com:90/foo');
122         $this->assertEquals('http://test.com:90/foo', $request->getUri());
123         $this->assertEquals('/foo', $request->getPathInfo());
124         $this->assertEquals('test.com', $request->getHost());
125         $this->assertEquals('test.com:90', $request->getHttpHost());
126         $this->assertEquals(90, $request->getPort());
127         $this->assertFalse($request->isSecure());
128
129         $request = Request::create('https://test.com:90/foo');
130         $this->assertEquals('https://test.com:90/foo', $request->getUri());
131         $this->assertEquals('/foo', $request->getPathInfo());
132         $this->assertEquals('test.com', $request->getHost());
133         $this->assertEquals('test.com:90', $request->getHttpHost());
134         $this->assertEquals(90, $request->getPort());
135         $this->assertTrue($request->isSecure());
136
137         $request = Request::create('https://127.0.0.1:90/foo');
138         $this->assertEquals('https://127.0.0.1:90/foo', $request->getUri());
139         $this->assertEquals('/foo', $request->getPathInfo());
140         $this->assertEquals('127.0.0.1', $request->getHost());
141         $this->assertEquals('127.0.0.1:90', $request->getHttpHost());
142         $this->assertEquals(90, $request->getPort());
143         $this->assertTrue($request->isSecure());
144
145         $request = Request::create('https://[::1]:90/foo');
146         $this->assertEquals('https://[::1]:90/foo', $request->getUri());
147         $this->assertEquals('/foo', $request->getPathInfo());
148         $this->assertEquals('[::1]', $request->getHost());
149         $this->assertEquals('[::1]:90', $request->getHttpHost());
150         $this->assertEquals(90, $request->getPort());
151         $this->assertTrue($request->isSecure());
152
153         $request = Request::create('https://[::1]/foo');
154         $this->assertEquals('https://[::1]/foo', $request->getUri());
155         $this->assertEquals('/foo', $request->getPathInfo());
156         $this->assertEquals('[::1]', $request->getHost());
157         $this->assertEquals('[::1]', $request->getHttpHost());
158         $this->assertEquals(443, $request->getPort());
159         $this->assertTrue($request->isSecure());
160
161         $json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}';
162         $request = Request::create('http://example.com/jsonrpc', 'POST', array(), array(), array(), array(), $json);
163         $this->assertEquals($json, $request->getContent());
164         $this->assertFalse($request->isSecure());
165
166         $request = Request::create('http://test.com');
167         $this->assertEquals('http://test.com/', $request->getUri());
168         $this->assertEquals('/', $request->getPathInfo());
169         $this->assertEquals('', $request->getQueryString());
170         $this->assertEquals(80, $request->getPort());
171         $this->assertEquals('test.com', $request->getHttpHost());
172         $this->assertFalse($request->isSecure());
173
174         $request = Request::create('http://test.com?test=1');
175         $this->assertEquals('http://test.com/?test=1', $request->getUri());
176         $this->assertEquals('/', $request->getPathInfo());
177         $this->assertEquals('test=1', $request->getQueryString());
178         $this->assertEquals(80, $request->getPort());
179         $this->assertEquals('test.com', $request->getHttpHost());
180         $this->assertFalse($request->isSecure());
181
182         $request = Request::create('http://test.com:90/?test=1');
183         $this->assertEquals('http://test.com:90/?test=1', $request->getUri());
184         $this->assertEquals('/', $request->getPathInfo());
185         $this->assertEquals('test=1', $request->getQueryString());
186         $this->assertEquals(90, $request->getPort());
187         $this->assertEquals('test.com:90', $request->getHttpHost());
188         $this->assertFalse($request->isSecure());
189
190         $request = Request::create('http://username:password@test.com');
191         $this->assertEquals('http://test.com/', $request->getUri());
192         $this->assertEquals('/', $request->getPathInfo());
193         $this->assertEquals('', $request->getQueryString());
194         $this->assertEquals(80, $request->getPort());
195         $this->assertEquals('test.com', $request->getHttpHost());
196         $this->assertEquals('username', $request->getUser());
197         $this->assertEquals('password', $request->getPassword());
198         $this->assertFalse($request->isSecure());
199
200         $request = Request::create('http://username@test.com');
201         $this->assertEquals('http://test.com/', $request->getUri());
202         $this->assertEquals('/', $request->getPathInfo());
203         $this->assertEquals('', $request->getQueryString());
204         $this->assertEquals(80, $request->getPort());
205         $this->assertEquals('test.com', $request->getHttpHost());
206         $this->assertEquals('username', $request->getUser());
207         $this->assertSame('', $request->getPassword());
208         $this->assertFalse($request->isSecure());
209
210         $request = Request::create('http://test.com/?foo');
211         $this->assertEquals('/?foo', $request->getRequestUri());
212         $this->assertEquals(array('foo' => ''), $request->query->all());
213
214         // assume rewrite rule: (.*) --> app/app.php; app/ is a symlink to a symfony web/ directory
215         $request = Request::create('http://test.com/apparthotel-1234', 'GET', array(), array(), array(),
216             array(
217                 'DOCUMENT_ROOT' => '/var/www/www.test.com',
218                 'SCRIPT_FILENAME' => '/var/www/www.test.com/app/app.php',
219                 'SCRIPT_NAME' => '/app/app.php',
220                 'PHP_SELF' => '/app/app.php/apparthotel-1234',
221             ));
222         $this->assertEquals('http://test.com/apparthotel-1234', $request->getUri());
223         $this->assertEquals('/apparthotel-1234', $request->getPathInfo());
224         $this->assertEquals('', $request->getQueryString());
225         $this->assertEquals(80, $request->getPort());
226         $this->assertEquals('test.com', $request->getHttpHost());
227         $this->assertFalse($request->isSecure());
228     }
229
230     public function testCreateCheckPrecedence()
231     {
232         // server is used by default
233         $request = Request::create('/', 'DELETE', array(), array(), array(), array(
234             'HTTP_HOST' => 'example.com',
235             'HTTPS' => 'on',
236             'SERVER_PORT' => 443,
237             'PHP_AUTH_USER' => 'fabien',
238             'PHP_AUTH_PW' => 'pa$$',
239             'QUERY_STRING' => 'foo=bar',
240             'CONTENT_TYPE' => 'application/json',
241         ));
242         $this->assertEquals('example.com', $request->getHost());
243         $this->assertEquals(443, $request->getPort());
244         $this->assertTrue($request->isSecure());
245         $this->assertEquals('fabien', $request->getUser());
246         $this->assertEquals('pa$$', $request->getPassword());
247         $this->assertEquals('', $request->getQueryString());
248         $this->assertEquals('application/json', $request->headers->get('CONTENT_TYPE'));
249
250         // URI has precedence over server
251         $request = Request::create('http://thomas:pokemon@example.net:8080/?foo=bar', 'GET', array(), array(), array(), array(
252             'HTTP_HOST' => 'example.com',
253             'HTTPS' => 'on',
254             'SERVER_PORT' => 443,
255         ));
256         $this->assertEquals('example.net', $request->getHost());
257         $this->assertEquals(8080, $request->getPort());
258         $this->assertFalse($request->isSecure());
259         $this->assertEquals('thomas', $request->getUser());
260         $this->assertEquals('pokemon', $request->getPassword());
261         $this->assertEquals('foo=bar', $request->getQueryString());
262     }
263
264     public function testDuplicate()
265     {
266         $request = new Request(array('foo' => 'bar'), array('foo' => 'bar'), array('foo' => 'bar'), array(), array(), array('HTTP_FOO' => 'bar'));
267         $dup = $request->duplicate();
268
269         $this->assertEquals($request->query->all(), $dup->query->all(), '->duplicate() duplicates a request an copy the current query parameters');
270         $this->assertEquals($request->request->all(), $dup->request->all(), '->duplicate() duplicates a request an copy the current request parameters');
271         $this->assertEquals($request->attributes->all(), $dup->attributes->all(), '->duplicate() duplicates a request an copy the current attributes');
272         $this->assertEquals($request->headers->all(), $dup->headers->all(), '->duplicate() duplicates a request an copy the current HTTP headers');
273
274         $dup = $request->duplicate(array('foo' => 'foobar'), array('foo' => 'foobar'), array('foo' => 'foobar'), array(), array(), array('HTTP_FOO' => 'foobar'));
275
276         $this->assertEquals(array('foo' => 'foobar'), $dup->query->all(), '->duplicate() overrides the query parameters if provided');
277         $this->assertEquals(array('foo' => 'foobar'), $dup->request->all(), '->duplicate() overrides the request parameters if provided');
278         $this->assertEquals(array('foo' => 'foobar'), $dup->attributes->all(), '->duplicate() overrides the attributes if provided');
279         $this->assertEquals(array('foo' => array('foobar')), $dup->headers->all(), '->duplicate() overrides the HTTP header if provided');
280     }
281
282     public function testDuplicateWithFormat()
283     {
284         $request = new Request(array(), array(), array('_format' => 'json'));
285         $dup = $request->duplicate();
286
287         $this->assertEquals('json', $dup->getRequestFormat());
288         $this->assertEquals('json', $dup->attributes->get('_format'));
289
290         $request = new Request();
291         $request->setRequestFormat('xml');
292         $dup = $request->duplicate();
293
294         $this->assertEquals('xml', $dup->getRequestFormat());
295     }
296
297     /**
298      * @dataProvider getFormatToMimeTypeMapProvider
299      */
300     public function testGetFormatFromMimeType($format, $mimeTypes)
301     {
302         $request = new Request();
303         foreach ($mimeTypes as $mime) {
304             $this->assertEquals($format, $request->getFormat($mime));
305         }
306         $request->setFormat($format, $mimeTypes);
307         foreach ($mimeTypes as $mime) {
308             $this->assertEquals($format, $request->getFormat($mime));
309
310             if (null !== $format) {
311                 $this->assertEquals($mimeTypes[0], $request->getMimeType($format));
312             }
313         }
314     }
315
316     public function testGetFormatFromMimeTypeWithParameters()
317     {
318         $request = new Request();
319         $this->assertEquals('json', $request->getFormat('application/json; charset=utf-8'));
320     }
321
322     public function testGetFormatWithCustomMimeType()
323     {
324         $request = new Request();
325         $request->setFormat('custom', 'application/vnd.foo.api;myversion=2.3');
326         $this->assertEquals('custom', $request->getFormat('application/vnd.foo.api;myversion=2.3'));
327     }
328
329     public function getFormatToMimeTypeMapProvider()
330     {
331         return array(
332             array(null, array(null, 'unexistent-mime-type')),
333             array('txt', array('text/plain')),
334             array('js', array('application/javascript', 'application/x-javascript', 'text/javascript')),
335             array('css', array('text/css')),
336             array('json', array('application/json', 'application/x-json')),
337             array('xml', array('text/xml', 'application/xml', 'application/x-xml')),
338             array('rdf', array('application/rdf+xml')),
339             array('atom', array('application/atom+xml')),
340         );
341     }
342
343     public function testGetUri()
344     {
345         $server = array();
346
347         // Standard Request on non default PORT
348         // http://host:8080/index.php/path/info?query=string
349
350         $server['HTTP_HOST'] = 'host:8080';
351         $server['SERVER_NAME'] = 'servername';
352         $server['SERVER_PORT'] = '8080';
353
354         $server['QUERY_STRING'] = 'query=string';
355         $server['REQUEST_URI'] = '/index.php/path/info?query=string';
356         $server['SCRIPT_NAME'] = '/index.php';
357         $server['PATH_INFO'] = '/path/info';
358         $server['PATH_TRANSLATED'] = 'redirect:/index.php/path/info';
359         $server['PHP_SELF'] = '/index_dev.php/path/info';
360         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
361
362         $request = new Request();
363
364         $request->initialize(array(), array(), array(), array(), array(), $server);
365
366         $this->assertEquals('http://host:8080/index.php/path/info?query=string', $request->getUri(), '->getUri() with non default port');
367
368         // Use std port number
369         $server['HTTP_HOST'] = 'host';
370         $server['SERVER_NAME'] = 'servername';
371         $server['SERVER_PORT'] = '80';
372
373         $request->initialize(array(), array(), array(), array(), array(), $server);
374
375         $this->assertEquals('http://host/index.php/path/info?query=string', $request->getUri(), '->getUri() with default port');
376
377         // Without HOST HEADER
378         unset($server['HTTP_HOST']);
379         $server['SERVER_NAME'] = 'servername';
380         $server['SERVER_PORT'] = '80';
381
382         $request->initialize(array(), array(), array(), array(), array(), $server);
383
384         $this->assertEquals('http://servername/index.php/path/info?query=string', $request->getUri(), '->getUri() with default port without HOST_HEADER');
385
386         // Request with URL REWRITING (hide index.php)
387         //   RewriteCond %{REQUEST_FILENAME} !-f
388         //   RewriteRule ^(.*)$ index.php [QSA,L]
389         // http://host:8080/path/info?query=string
390         $server = array();
391         $server['HTTP_HOST'] = 'host:8080';
392         $server['SERVER_NAME'] = 'servername';
393         $server['SERVER_PORT'] = '8080';
394
395         $server['REDIRECT_QUERY_STRING'] = 'query=string';
396         $server['REDIRECT_URL'] = '/path/info';
397         $server['SCRIPT_NAME'] = '/index.php';
398         $server['QUERY_STRING'] = 'query=string';
399         $server['REQUEST_URI'] = '/path/info?toto=test&1=1';
400         $server['SCRIPT_NAME'] = '/index.php';
401         $server['PHP_SELF'] = '/index.php';
402         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
403
404         $request->initialize(array(), array(), array(), array(), array(), $server);
405         $this->assertEquals('http://host:8080/path/info?query=string', $request->getUri(), '->getUri() with rewrite');
406
407         // Use std port number
408         //  http://host/path/info?query=string
409         $server['HTTP_HOST'] = 'host';
410         $server['SERVER_NAME'] = 'servername';
411         $server['SERVER_PORT'] = '80';
412
413         $request->initialize(array(), array(), array(), array(), array(), $server);
414
415         $this->assertEquals('http://host/path/info?query=string', $request->getUri(), '->getUri() with rewrite and default port');
416
417         // Without HOST HEADER
418         unset($server['HTTP_HOST']);
419         $server['SERVER_NAME'] = 'servername';
420         $server['SERVER_PORT'] = '80';
421
422         $request->initialize(array(), array(), array(), array(), array(), $server);
423
424         $this->assertEquals('http://servername/path/info?query=string', $request->getUri(), '->getUri() with rewrite, default port without HOST_HEADER');
425
426         // With encoded characters
427
428         $server = array(
429             'HTTP_HOST' => 'host:8080',
430             'SERVER_NAME' => 'servername',
431             'SERVER_PORT' => '8080',
432             'QUERY_STRING' => 'query=string',
433             'REQUEST_URI' => '/ba%20se/index_dev.php/foo%20bar/in+fo?query=string',
434             'SCRIPT_NAME' => '/ba se/index_dev.php',
435             'PATH_TRANSLATED' => 'redirect:/index.php/foo bar/in+fo',
436             'PHP_SELF' => '/ba se/index_dev.php/path/info',
437             'SCRIPT_FILENAME' => '/some/where/ba se/index_dev.php',
438         );
439
440         $request->initialize(array(), array(), array(), array(), array(), $server);
441
442         $this->assertEquals(
443             'http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string',
444             $request->getUri()
445         );
446
447         // with user info
448
449         $server['PHP_AUTH_USER'] = 'fabien';
450         $request->initialize(array(), array(), array(), array(), array(), $server);
451         $this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri());
452
453         $server['PHP_AUTH_PW'] = 'symfony';
454         $request->initialize(array(), array(), array(), array(), array(), $server);
455         $this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri());
456     }
457
458     public function testGetUriForPath()
459     {
460         $request = Request::create('http://test.com/foo?bar=baz');
461         $this->assertEquals('http://test.com/some/path', $request->getUriForPath('/some/path'));
462
463         $request = Request::create('http://test.com:90/foo?bar=baz');
464         $this->assertEquals('http://test.com:90/some/path', $request->getUriForPath('/some/path'));
465
466         $request = Request::create('https://test.com/foo?bar=baz');
467         $this->assertEquals('https://test.com/some/path', $request->getUriForPath('/some/path'));
468
469         $request = Request::create('https://test.com:90/foo?bar=baz');
470         $this->assertEquals('https://test.com:90/some/path', $request->getUriForPath('/some/path'));
471
472         $server = array();
473
474         // Standard Request on non default PORT
475         // http://host:8080/index.php/path/info?query=string
476
477         $server['HTTP_HOST'] = 'host:8080';
478         $server['SERVER_NAME'] = 'servername';
479         $server['SERVER_PORT'] = '8080';
480
481         $server['QUERY_STRING'] = 'query=string';
482         $server['REQUEST_URI'] = '/index.php/path/info?query=string';
483         $server['SCRIPT_NAME'] = '/index.php';
484         $server['PATH_INFO'] = '/path/info';
485         $server['PATH_TRANSLATED'] = 'redirect:/index.php/path/info';
486         $server['PHP_SELF'] = '/index_dev.php/path/info';
487         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
488
489         $request = new Request();
490
491         $request->initialize(array(), array(), array(), array(), array(), $server);
492
493         $this->assertEquals('http://host:8080/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with non default port');
494
495         // Use std port number
496         $server['HTTP_HOST'] = 'host';
497         $server['SERVER_NAME'] = 'servername';
498         $server['SERVER_PORT'] = '80';
499
500         $request->initialize(array(), array(), array(), array(), array(), $server);
501
502         $this->assertEquals('http://host/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with default port');
503
504         // Without HOST HEADER
505         unset($server['HTTP_HOST']);
506         $server['SERVER_NAME'] = 'servername';
507         $server['SERVER_PORT'] = '80';
508
509         $request->initialize(array(), array(), array(), array(), array(), $server);
510
511         $this->assertEquals('http://servername/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with default port without HOST_HEADER');
512
513         // Request with URL REWRITING (hide index.php)
514         //   RewriteCond %{REQUEST_FILENAME} !-f
515         //   RewriteRule ^(.*)$ index.php [QSA,L]
516         // http://host:8080/path/info?query=string
517         $server = array();
518         $server['HTTP_HOST'] = 'host:8080';
519         $server['SERVER_NAME'] = 'servername';
520         $server['SERVER_PORT'] = '8080';
521
522         $server['REDIRECT_QUERY_STRING'] = 'query=string';
523         $server['REDIRECT_URL'] = '/path/info';
524         $server['SCRIPT_NAME'] = '/index.php';
525         $server['QUERY_STRING'] = 'query=string';
526         $server['REQUEST_URI'] = '/path/info?toto=test&1=1';
527         $server['SCRIPT_NAME'] = '/index.php';
528         $server['PHP_SELF'] = '/index.php';
529         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
530
531         $request->initialize(array(), array(), array(), array(), array(), $server);
532         $this->assertEquals('http://host:8080/some/path', $request->getUriForPath('/some/path'), '->getUri() with rewrite');
533
534         // Use std port number
535         //  http://host/path/info?query=string
536         $server['HTTP_HOST'] = 'host';
537         $server['SERVER_NAME'] = 'servername';
538         $server['SERVER_PORT'] = '80';
539
540         $request->initialize(array(), array(), array(), array(), array(), $server);
541
542         $this->assertEquals('http://host/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite and default port');
543
544         // Without HOST HEADER
545         unset($server['HTTP_HOST']);
546         $server['SERVER_NAME'] = 'servername';
547         $server['SERVER_PORT'] = '80';
548
549         $request->initialize(array(), array(), array(), array(), array(), $server);
550
551         $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite, default port without HOST_HEADER');
552         $this->assertEquals('servername', $request->getHttpHost());
553
554         // with user info
555
556         $server['PHP_AUTH_USER'] = 'fabien';
557         $request->initialize(array(), array(), array(), array(), array(), $server);
558         $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'));
559
560         $server['PHP_AUTH_PW'] = 'symfony';
561         $request->initialize(array(), array(), array(), array(), array(), $server);
562         $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'));
563     }
564
565     /**
566      * @dataProvider getRelativeUriForPathData()
567      */
568     public function testGetRelativeUriForPath($expected, $pathinfo, $path)
569     {
570         $this->assertEquals($expected, Request::create($pathinfo)->getRelativeUriForPath($path));
571     }
572
573     public function getRelativeUriForPathData()
574     {
575         return array(
576             array('me.png', '/foo', '/me.png'),
577             array('../me.png', '/foo/bar', '/me.png'),
578             array('me.png', '/foo/bar', '/foo/me.png'),
579             array('../baz/me.png', '/foo/bar/b', '/foo/baz/me.png'),
580             array('../../fooz/baz/me.png', '/foo/bar/b', '/fooz/baz/me.png'),
581             array('baz/me.png', '/foo/bar/b', 'baz/me.png'),
582         );
583     }
584
585     public function testGetUserInfo()
586     {
587         $request = new Request();
588
589         $server = array('PHP_AUTH_USER' => 'fabien');
590         $request->initialize(array(), array(), array(), array(), array(), $server);
591         $this->assertEquals('fabien', $request->getUserInfo());
592
593         $server['PHP_AUTH_USER'] = '0';
594         $request->initialize(array(), array(), array(), array(), array(), $server);
595         $this->assertEquals('0', $request->getUserInfo());
596
597         $server['PHP_AUTH_PW'] = '0';
598         $request->initialize(array(), array(), array(), array(), array(), $server);
599         $this->assertEquals('0:0', $request->getUserInfo());
600     }
601
602     public function testGetSchemeAndHttpHost()
603     {
604         $request = new Request();
605
606         $server = array();
607         $server['SERVER_NAME'] = 'servername';
608         $server['SERVER_PORT'] = '90';
609         $request->initialize(array(), array(), array(), array(), array(), $server);
610         $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
611
612         $server['PHP_AUTH_USER'] = 'fabien';
613         $request->initialize(array(), array(), array(), array(), array(), $server);
614         $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
615
616         $server['PHP_AUTH_USER'] = '0';
617         $request->initialize(array(), array(), array(), array(), array(), $server);
618         $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
619
620         $server['PHP_AUTH_PW'] = '0';
621         $request->initialize(array(), array(), array(), array(), array(), $server);
622         $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
623     }
624
625     /**
626      * @dataProvider getQueryStringNormalizationData
627      */
628     public function testGetQueryString($query, $expectedQuery, $msg)
629     {
630         $request = new Request();
631
632         $request->server->set('QUERY_STRING', $query);
633         $this->assertSame($expectedQuery, $request->getQueryString(), $msg);
634     }
635
636     public function getQueryStringNormalizationData()
637     {
638         return array(
639             array('foo', 'foo', 'works with valueless parameters'),
640             array('foo=', 'foo=', 'includes a dangling equal sign'),
641             array('bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'),
642             array('foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'),
643
644             // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
645             // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str.
646             array('him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'),
647
648             array('foo[]=1&foo[]=2', 'foo%5B%5D=1&foo%5B%5D=2', 'allows array notation'),
649             array('foo=1&foo=2', 'foo=1&foo=2', 'allows repeated parameters'),
650             array('pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'),
651             array('0', '0', 'allows "0"'),
652             array('Jane Doe&John%20Doe', 'Jane%20Doe&John%20Doe', 'normalizes encoding in keys'),
653             array('her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'),
654             array('foo=bar&&&test&&', 'foo=bar&test', 'removes unneeded delimiters'),
655             array('formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'),
656
657             // Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
658             // PHP also does not include them when building _GET.
659             array('foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'),
660         );
661     }
662
663     public function testGetQueryStringReturnsNull()
664     {
665         $request = new Request();
666
667         $this->assertNull($request->getQueryString(), '->getQueryString() returns null for non-existent query string');
668
669         $request->server->set('QUERY_STRING', '');
670         $this->assertNull($request->getQueryString(), '->getQueryString() returns null for empty query string');
671     }
672
673     public function testGetHost()
674     {
675         $request = new Request();
676
677         $request->initialize(array('foo' => 'bar'));
678         $this->assertEquals('', $request->getHost(), '->getHost() return empty string if not initialized');
679
680         $request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.example.com'));
681         $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from Host Header');
682
683         // Host header with port number
684         $request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.example.com:8080'));
685         $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from Host Header with port number');
686
687         // Server values
688         $request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.example.com'));
689         $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from server name');
690
691         $request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.example.com', 'HTTP_HOST' => 'www.host.com'));
692         $this->assertEquals('www.host.com', $request->getHost(), '->getHost() value from Host header has priority over SERVER_NAME ');
693     }
694
695     public function testGetPort()
696     {
697         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
698             'HTTP_X_FORWARDED_PROTO' => 'https',
699             'HTTP_X_FORWARDED_PORT' => '443',
700         ));
701         $port = $request->getPort();
702
703         $this->assertEquals(80, $port, 'Without trusted proxies FORWARDED_PROTO and FORWARDED_PORT are ignored.');
704
705         Request::setTrustedProxies(array('1.1.1.1'));
706         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
707             'HTTP_X_FORWARDED_PROTO' => 'https',
708             'HTTP_X_FORWARDED_PORT' => '8443',
709         ));
710         $this->assertEquals(80, $request->getPort(), 'With PROTO and PORT on untrusted connection server value takes precedence.');
711         $request->server->set('REMOTE_ADDR', '1.1.1.1');
712         $this->assertEquals(8443, $request->getPort(), 'With PROTO and PORT set PORT takes precedence.');
713
714         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
715             'HTTP_X_FORWARDED_PROTO' => 'https',
716         ));
717         $this->assertEquals(80, $request->getPort(), 'With only PROTO set getPort() ignores trusted headers on untrusted connection.');
718         $request->server->set('REMOTE_ADDR', '1.1.1.1');
719         $this->assertEquals(443, $request->getPort(), 'With only PROTO set getPort() defaults to 443.');
720
721         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
722             'HTTP_X_FORWARDED_PROTO' => 'http',
723         ));
724         $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() ignores trusted headers on untrusted connection.');
725         $request->server->set('REMOTE_ADDR', '1.1.1.1');
726         $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() returns port of the original request.');
727
728         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
729             'HTTP_X_FORWARDED_PROTO' => 'On',
730         ));
731         $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is On, getPort() ignores trusted headers on untrusted connection.');
732         $request->server->set('REMOTE_ADDR', '1.1.1.1');
733         $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is On, getPort() defaults to 443.');
734
735         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
736             'HTTP_X_FORWARDED_PROTO' => '1',
737         ));
738         $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is 1, getPort() ignores trusted headers on untrusted connection.');
739         $request->server->set('REMOTE_ADDR', '1.1.1.1');
740         $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is 1, getPort() defaults to 443.');
741
742         $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
743             'HTTP_X_FORWARDED_PROTO' => 'something-else',
744         ));
745         $port = $request->getPort();
746         $this->assertEquals(80, $port, 'With only PROTO set and value is not recognized, getPort() defaults to 80.');
747
748         Request::setTrustedProxies(array());
749     }
750
751     /**
752      * @expectedException \RuntimeException
753      */
754     public function testGetHostWithFakeHttpHostValue()
755     {
756         $request = new Request();
757         $request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.host.com?query=string'));
758         $request->getHost();
759     }
760
761     public function testGetSetMethod()
762     {
763         $request = new Request();
764
765         $this->assertEquals('GET', $request->getMethod(), '->getMethod() returns GET if no method is defined');
766
767         $request->setMethod('get');
768         $this->assertEquals('GET', $request->getMethod(), '->getMethod() returns an uppercased string');
769
770         $request->setMethod('PURGE');
771         $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method even if it is not a standard one');
772
773         $request->setMethod('POST');
774         $this->assertEquals('POST', $request->getMethod(), '->getMethod() returns the method POST if no _method is defined');
775
776         $request->setMethod('POST');
777         $request->request->set('_method', 'purge');
778         $this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled');
779
780         $request = new Request();
781         $request->setMethod('POST');
782         $request->request->set('_method', 'purge');
783
784         $this->assertFalse(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be disabled by default');
785
786         Request::enableHttpMethodParameterOverride();
787
788         $this->assertTrue(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be enabled now but it is not');
789
790         $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
791         $this->disableHttpMethodParameterOverride();
792
793         $request = new Request();
794         $request->setMethod('POST');
795         $request->query->set('_method', 'purge');
796         $this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled');
797
798         $request = new Request();
799         $request->setMethod('POST');
800         $request->query->set('_method', 'purge');
801         Request::enableHttpMethodParameterOverride();
802         $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
803         $this->disableHttpMethodParameterOverride();
804
805         $request = new Request();
806         $request->setMethod('POST');
807         $request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
808         $this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override even though _method is set if defined and POST');
809
810         $request = new Request();
811         $request->setMethod('POST');
812         $request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
813         $this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override if defined and POST');
814     }
815
816     /**
817      * @dataProvider getClientIpsProvider
818      */
819     public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
820     {
821         $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies);
822
823         $this->assertEquals($expected[0], $request->getClientIp());
824
825         Request::setTrustedProxies(array());
826     }
827
828     /**
829      * @dataProvider getClientIpsProvider
830      */
831     public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
832     {
833         $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies);
834
835         $this->assertEquals($expected, $request->getClientIps());
836
837         Request::setTrustedProxies(array());
838     }
839
840     /**
841      * @dataProvider getClientIpsForwardedProvider
842      */
843     public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies)
844     {
845         $request = $this->getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies);
846
847         $this->assertEquals($expected, $request->getClientIps());
848
849         Request::setTrustedProxies(array());
850     }
851
852     public function getClientIpsForwardedProvider()
853     {
854         //              $expected                                  $remoteAddr  $httpForwarded                                       $trustedProxies
855         return array(
856             array(array('127.0.0.1'),                              '127.0.0.1', 'for="_gazonk"',                                      null),
857             array(array('127.0.0.1'),                              '127.0.0.1', 'for="_gazonk"',                                      array('127.0.0.1')),
858             array(array('88.88.88.88'),                            '127.0.0.1', 'for="88.88.88.88:80"',                               array('127.0.0.1')),
859             array(array('192.0.2.60'),                             '::1',       'for=192.0.2.60;proto=http;by=203.0.113.43',          array('::1')),
860             array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1',       'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3',       array('::1')),
861             array(array('2001:db8:cafe::17'),                      '::1',       'for="[2001:db8:cafe::17]:4711',                      array('::1')),
862         );
863     }
864
865     public function getClientIpsProvider()
866     {
867         //        $expected                   $remoteAddr                $httpForwardedFor            $trustedProxies
868         return array(
869             // simple IPv4
870             array(array('88.88.88.88'),              '88.88.88.88',              null,                        null),
871             // trust the IPv4 remote addr
872             array(array('88.88.88.88'),              '88.88.88.88',              null,                        array('88.88.88.88')),
873
874             // simple IPv6
875             array(array('::1'),                      '::1',                      null,                        null),
876             // trust the IPv6 remote addr
877             array(array('::1'),                      '::1',                      null,                        array('::1')),
878
879             // forwarded for with remote IPv4 addr not trusted
880             array(array('127.0.0.1'),                '127.0.0.1',                '88.88.88.88',               null),
881             // forwarded for with remote IPv4 addr trusted
882             array(array('88.88.88.88'),              '127.0.0.1',                '88.88.88.88',               array('127.0.0.1')),
883             // forwarded for with remote IPv4 and all FF addrs trusted
884             array(array('88.88.88.88'),              '127.0.0.1',                '88.88.88.88',               array('127.0.0.1', '88.88.88.88')),
885             // forwarded for with remote IPv4 range trusted
886             array(array('88.88.88.88'),              '123.45.67.89',             '88.88.88.88',               array('123.45.67.0/24')),
887
888             // forwarded for with remote IPv6 addr not trusted
889             array(array('1620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3',  null),
890             // forwarded for with remote IPv6 addr trusted
891             array(array('2620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3',  array('1620:0:1cfe:face:b00c::3')),
892             // forwarded for with remote IPv6 range trusted
893             array(array('88.88.88.88'),              '2a01:198:603:0:396e:4789:8e99:890f', '88.88.88.88',     array('2a01:198:603:0::/65')),
894
895             // multiple forwarded for with remote IPv4 addr trusted
896             array(array('88.88.88.88', '87.65.43.21', '127.0.0.1'), '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89')),
897             // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted
898             array(array('87.65.43.21', '127.0.0.1'), '123.45.67.89',             '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '88.88.88.88')),
899             // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle
900             array(array('88.88.88.88', '127.0.0.1'), '123.45.67.89',             '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '87.65.43.21')),
901             // multiple forwarded for with remote IPv4 addr and all reverse proxies trusted
902             array(array('127.0.0.1'),                '123.45.67.89',             '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '87.65.43.21', '88.88.88.88', '127.0.0.1')),
903
904             // multiple forwarded for with remote IPv6 addr trusted
905             array(array('2620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3')),
906             // multiple forwarded for with remote IPv6 addr and some reverse proxies trusted
907             array(array('3620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3')),
908             // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle
909             array(array('2620:0:1cfe:face:b00c::3', '4620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '4620:0:1cfe:face:b00c::3,3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3')),
910
911             // client IP with port
912             array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88:12345, 127.0.0.1', array('127.0.0.1')),
913
914             // invalid forwarded IP is ignored
915             array(array('88.88.88.88'), '127.0.0.1', 'unknown,88.88.88.88', array('127.0.0.1')),
916             array(array('88.88.88.88'), '127.0.0.1', '}__test|O:21:&quot;JDatabaseDriverMysqli&quot;:3:{s:2,88.88.88.88', array('127.0.0.1')),
917         );
918     }
919
920     /**
921      * @expectedException \Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException
922      * @dataProvider getClientIpsWithConflictingHeadersProvider
923      */
924     public function testGetClientIpsWithConflictingHeaders($httpForwarded, $httpXForwardedFor)
925     {
926         $request = new Request();
927
928         $server = array(
929             'REMOTE_ADDR' => '88.88.88.88',
930             'HTTP_FORWARDED' => $httpForwarded,
931             'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
932         );
933
934         Request::setTrustedProxies(array('88.88.88.88'));
935
936         $request->initialize(array(), array(), array(), array(), array(), $server);
937
938         $request->getClientIps();
939     }
940
941     public function getClientIpsWithConflictingHeadersProvider()
942     {
943         //        $httpForwarded                   $httpXForwardedFor
944         return array(
945             array('for=87.65.43.21',                 '192.0.2.60'),
946             array('for=87.65.43.21, for=192.0.2.60', '192.0.2.60'),
947             array('for=192.0.2.60',                  '192.0.2.60,87.65.43.21'),
948             array('for="::face", for=192.0.2.60',    '192.0.2.60,192.0.2.43'),
949             array('for=87.65.43.21, for=192.0.2.60', '192.0.2.60,87.65.43.21'),
950         );
951     }
952
953     /**
954      * @dataProvider getClientIpsWithAgreeingHeadersProvider
955      */
956     public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwardedFor, $expectedIps)
957     {
958         $request = new Request();
959
960         $server = array(
961             'REMOTE_ADDR' => '88.88.88.88',
962             'HTTP_FORWARDED' => $httpForwarded,
963             'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
964         );
965
966         Request::setTrustedProxies(array('88.88.88.88'));
967
968         $request->initialize(array(), array(), array(), array(), array(), $server);
969
970         $clientIps = $request->getClientIps();
971
972         Request::setTrustedProxies(array());
973
974         $this->assertSame($expectedIps, $clientIps);
975     }
976
977     public function getClientIpsWithAgreeingHeadersProvider()
978     {
979         //        $httpForwarded                               $httpXForwardedFor
980         return array(
981             array('for="192.0.2.60"',                          '192.0.2.60',             array('192.0.2.60')),
982             array('for=192.0.2.60, for=87.65.43.21',           '192.0.2.60,87.65.43.21', array('87.65.43.21', '192.0.2.60')),
983             array('for="[::face]", for=192.0.2.60',            '::face,192.0.2.60',      array('192.0.2.60', '::face')),
984             array('for="192.0.2.60:80"',                       '192.0.2.60',             array('192.0.2.60')),
985             array('for=192.0.2.60;proto=http;by=203.0.113.43', '192.0.2.60',             array('192.0.2.60')),
986             array('for="[2001:db8:cafe::17]:4711"',            '2001:db8:cafe::17',      array('2001:db8:cafe::17')),
987         );
988     }
989
990     public function testGetContentWorksTwiceInDefaultMode()
991     {
992         $req = new Request();
993         $this->assertEquals('', $req->getContent());
994         $this->assertEquals('', $req->getContent());
995     }
996
997     public function testGetContentReturnsResource()
998     {
999         $req = new Request();
1000         $retval = $req->getContent(true);
1001         $this->assertInternalType('resource', $retval);
1002         $this->assertEquals('', fread($retval, 1));
1003         $this->assertTrue(feof($retval));
1004     }
1005
1006     public function testGetContentReturnsResourceWhenContentSetInConstructor()
1007     {
1008         $req = new Request(array(), array(), array(), array(), array(), array(), 'MyContent');
1009         $resource = $req->getContent(true);
1010
1011         $this->assertInternalType('resource', $resource);
1012         $this->assertEquals('MyContent', stream_get_contents($resource));
1013     }
1014
1015     public function testContentAsResource()
1016     {
1017         $resource = fopen('php://memory', 'r+');
1018         fwrite($resource, 'My other content');
1019         rewind($resource);
1020
1021         $req = new Request(array(), array(), array(), array(), array(), array(), $resource);
1022         $this->assertEquals('My other content', stream_get_contents($req->getContent(true)));
1023         $this->assertEquals('My other content', $req->getContent());
1024     }
1025
1026     /**
1027      * @expectedException \LogicException
1028      * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
1029      */
1030     public function testGetContentCantBeCalledTwiceWithResources($first, $second)
1031     {
1032         if (\PHP_VERSION_ID >= 50600) {
1033             $this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.');
1034         }
1035
1036         $req = new Request();
1037         $req->getContent($first);
1038         $req->getContent($second);
1039     }
1040
1041     public function getContentCantBeCalledTwiceWithResourcesProvider()
1042     {
1043         return array(
1044             'Resource then fetch' => array(true, false),
1045             'Resource then resource' => array(true, true),
1046         );
1047     }
1048
1049     /**
1050      * @dataProvider getContentCanBeCalledTwiceWithResourcesProvider
1051      * @requires PHP 5.6
1052      */
1053     public function testGetContentCanBeCalledTwiceWithResources($first, $second)
1054     {
1055         $req = new Request();
1056         $a = $req->getContent($first);
1057         $b = $req->getContent($second);
1058
1059         if ($first) {
1060             $a = stream_get_contents($a);
1061         }
1062
1063         if ($second) {
1064             $b = stream_get_contents($b);
1065         }
1066
1067         $this->assertSame($a, $b);
1068     }
1069
1070     public function getContentCanBeCalledTwiceWithResourcesProvider()
1071     {
1072         return array(
1073             'Fetch then fetch' => array(false, false),
1074             'Fetch then resource' => array(false, true),
1075             'Resource then fetch' => array(true, false),
1076             'Resource then resource' => array(true, true),
1077         );
1078     }
1079
1080     public function provideOverloadedMethods()
1081     {
1082         return array(
1083             array('PUT'),
1084             array('DELETE'),
1085             array('PATCH'),
1086             array('put'),
1087             array('delete'),
1088             array('patch'),
1089         );
1090     }
1091
1092     /**
1093      * @dataProvider provideOverloadedMethods
1094      */
1095     public function testCreateFromGlobals($method)
1096     {
1097         $normalizedMethod = strtoupper($method);
1098
1099         $_GET['foo1'] = 'bar1';
1100         $_POST['foo2'] = 'bar2';
1101         $_COOKIE['foo3'] = 'bar3';
1102         $_FILES['foo4'] = array('bar4');
1103         $_SERVER['foo5'] = 'bar5';
1104
1105         $request = Request::createFromGlobals();
1106         $this->assertEquals('bar1', $request->query->get('foo1'), '::fromGlobals() uses values from $_GET');
1107         $this->assertEquals('bar2', $request->request->get('foo2'), '::fromGlobals() uses values from $_POST');
1108         $this->assertEquals('bar3', $request->cookies->get('foo3'), '::fromGlobals() uses values from $_COOKIE');
1109         $this->assertEquals(array('bar4'), $request->files->get('foo4'), '::fromGlobals() uses values from $_FILES');
1110         $this->assertEquals('bar5', $request->server->get('foo5'), '::fromGlobals() uses values from $_SERVER');
1111
1112         unset($_GET['foo1'], $_POST['foo2'], $_COOKIE['foo3'], $_FILES['foo4'], $_SERVER['foo5']);
1113
1114         $_SERVER['REQUEST_METHOD'] = $method;
1115         $_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1116         $request = RequestContentProxy::createFromGlobals();
1117         $this->assertEquals($normalizedMethod, $request->getMethod());
1118         $this->assertEquals('mycontent', $request->request->get('content'));
1119
1120         unset($_SERVER['REQUEST_METHOD'], $_SERVER['CONTENT_TYPE']);
1121
1122         Request::createFromGlobals();
1123         Request::enableHttpMethodParameterOverride();
1124         $_POST['_method'] = $method;
1125         $_POST['foo6'] = 'bar6';
1126         $_SERVER['REQUEST_METHOD'] = 'PoSt';
1127         $request = Request::createFromGlobals();
1128         $this->assertEquals($normalizedMethod, $request->getMethod());
1129         $this->assertEquals('POST', $request->getRealMethod());
1130         $this->assertEquals('bar6', $request->request->get('foo6'));
1131
1132         unset($_POST['_method'], $_POST['foo6'], $_SERVER['REQUEST_METHOD']);
1133         $this->disableHttpMethodParameterOverride();
1134     }
1135
1136     public function testOverrideGlobals()
1137     {
1138         $request = new Request();
1139         $request->initialize(array('foo' => 'bar'));
1140
1141         // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it
1142         $server = $_SERVER;
1143
1144         $request->overrideGlobals();
1145
1146         $this->assertEquals(array('foo' => 'bar'), $_GET);
1147
1148         $request->initialize(array(), array('foo' => 'bar'));
1149         $request->overrideGlobals();
1150
1151         $this->assertEquals(array('foo' => 'bar'), $_POST);
1152
1153         $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
1154
1155         $request->headers->set('X_FORWARDED_PROTO', 'https');
1156
1157         Request::setTrustedProxies(array('1.1.1.1'));
1158         $this->assertFalse($request->isSecure());
1159         $request->server->set('REMOTE_ADDR', '1.1.1.1');
1160         $this->assertTrue($request->isSecure());
1161         Request::setTrustedProxies(array());
1162
1163         $request->overrideGlobals();
1164
1165         $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
1166
1167         $request->headers->set('CONTENT_TYPE', 'multipart/form-data');
1168         $request->headers->set('CONTENT_LENGTH', 12345);
1169
1170         $request->overrideGlobals();
1171
1172         $this->assertArrayHasKey('CONTENT_TYPE', $_SERVER);
1173         $this->assertArrayHasKey('CONTENT_LENGTH', $_SERVER);
1174
1175         $request->initialize(array('foo' => 'bar', 'baz' => 'foo'));
1176         $request->query->remove('baz');
1177
1178         $request->overrideGlobals();
1179
1180         $this->assertEquals(array('foo' => 'bar'), $_GET);
1181         $this->assertEquals('foo=bar', $_SERVER['QUERY_STRING']);
1182         $this->assertEquals('foo=bar', $request->server->get('QUERY_STRING'));
1183
1184         // restore initial $_SERVER array
1185         $_SERVER = $server;
1186     }
1187
1188     public function testGetScriptName()
1189     {
1190         $request = new Request();
1191         $this->assertEquals('', $request->getScriptName());
1192
1193         $server = array();
1194         $server['SCRIPT_NAME'] = '/index.php';
1195
1196         $request->initialize(array(), array(), array(), array(), array(), $server);
1197
1198         $this->assertEquals('/index.php', $request->getScriptName());
1199
1200         $server = array();
1201         $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
1202         $request->initialize(array(), array(), array(), array(), array(), $server);
1203
1204         $this->assertEquals('/frontend.php', $request->getScriptName());
1205
1206         $server = array();
1207         $server['SCRIPT_NAME'] = '/index.php';
1208         $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
1209         $request->initialize(array(), array(), array(), array(), array(), $server);
1210
1211         $this->assertEquals('/index.php', $request->getScriptName());
1212     }
1213
1214     public function testGetBasePath()
1215     {
1216         $request = new Request();
1217         $this->assertEquals('', $request->getBasePath());
1218
1219         $server = array();
1220         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1221         $request->initialize(array(), array(), array(), array(), array(), $server);
1222         $this->assertEquals('', $request->getBasePath());
1223
1224         $server = array();
1225         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1226         $server['SCRIPT_NAME'] = '/index.php';
1227         $request->initialize(array(), array(), array(), array(), array(), $server);
1228
1229         $this->assertEquals('', $request->getBasePath());
1230
1231         $server = array();
1232         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1233         $server['PHP_SELF'] = '/index.php';
1234         $request->initialize(array(), array(), array(), array(), array(), $server);
1235
1236         $this->assertEquals('', $request->getBasePath());
1237
1238         $server = array();
1239         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1240         $server['ORIG_SCRIPT_NAME'] = '/index.php';
1241         $request->initialize(array(), array(), array(), array(), array(), $server);
1242
1243         $this->assertEquals('', $request->getBasePath());
1244     }
1245
1246     public function testGetPathInfo()
1247     {
1248         $request = new Request();
1249         $this->assertEquals('/', $request->getPathInfo());
1250
1251         $server = array();
1252         $server['REQUEST_URI'] = '/path/info';
1253         $request->initialize(array(), array(), array(), array(), array(), $server);
1254
1255         $this->assertEquals('/path/info', $request->getPathInfo());
1256
1257         $server = array();
1258         $server['REQUEST_URI'] = '/path%20test/info';
1259         $request->initialize(array(), array(), array(), array(), array(), $server);
1260
1261         $this->assertEquals('/path%20test/info', $request->getPathInfo());
1262
1263         $server = array();
1264         $server['REQUEST_URI'] = '?a=b';
1265         $request->initialize(array(), array(), array(), array(), array(), $server);
1266
1267         $this->assertEquals('/', $request->getPathInfo());
1268     }
1269
1270     public function testGetPreferredLanguage()
1271     {
1272         $request = new Request();
1273         $this->assertNull($request->getPreferredLanguage());
1274         $this->assertNull($request->getPreferredLanguage(array()));
1275         $this->assertEquals('fr', $request->getPreferredLanguage(array('fr')));
1276         $this->assertEquals('fr', $request->getPreferredLanguage(array('fr', 'en')));
1277         $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'fr')));
1278         $this->assertEquals('fr-ch', $request->getPreferredLanguage(array('fr-ch', 'fr-fr')));
1279
1280         $request = new Request();
1281         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1282         $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'en-us')));
1283
1284         $request = new Request();
1285         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1286         $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
1287
1288         $request = new Request();
1289         $request->headers->set('Accept-language', 'zh, en-us; q=0.8');
1290         $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
1291
1292         $request = new Request();
1293         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, fr-fr; q=0.6, fr; q=0.5');
1294         $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
1295     }
1296
1297     public function testIsXmlHttpRequest()
1298     {
1299         $request = new Request();
1300         $this->assertFalse($request->isXmlHttpRequest());
1301
1302         $request->headers->set('X-Requested-With', 'XMLHttpRequest');
1303         $this->assertTrue($request->isXmlHttpRequest());
1304
1305         $request->headers->remove('X-Requested-With');
1306         $this->assertFalse($request->isXmlHttpRequest());
1307     }
1308
1309     /**
1310      * @requires extension intl
1311      */
1312     public function testIntlLocale()
1313     {
1314         $request = new Request();
1315
1316         $request->setDefaultLocale('fr');
1317         $this->assertEquals('fr', $request->getLocale());
1318         $this->assertEquals('fr', \Locale::getDefault());
1319
1320         $request->setLocale('en');
1321         $this->assertEquals('en', $request->getLocale());
1322         $this->assertEquals('en', \Locale::getDefault());
1323
1324         $request->setDefaultLocale('de');
1325         $this->assertEquals('en', $request->getLocale());
1326         $this->assertEquals('en', \Locale::getDefault());
1327     }
1328
1329     public function testGetCharsets()
1330     {
1331         $request = new Request();
1332         $this->assertEquals(array(), $request->getCharsets());
1333         $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
1334         $this->assertEquals(array(), $request->getCharsets()); // testing caching
1335
1336         $request = new Request();
1337         $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
1338         $this->assertEquals(array('ISO-8859-1', 'US-ASCII', 'UTF-8', 'ISO-10646-UCS-2'), $request->getCharsets());
1339
1340         $request = new Request();
1341         $request->headers->set('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7');
1342         $this->assertEquals(array('ISO-8859-1', 'utf-8', '*'), $request->getCharsets());
1343     }
1344
1345     public function testGetEncodings()
1346     {
1347         $request = new Request();
1348         $this->assertEquals(array(), $request->getEncodings());
1349         $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch');
1350         $this->assertEquals(array(), $request->getEncodings()); // testing caching
1351
1352         $request = new Request();
1353         $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch');
1354         $this->assertEquals(array('gzip', 'deflate', 'sdch'), $request->getEncodings());
1355
1356         $request = new Request();
1357         $request->headers->set('Accept-Encoding', 'gzip;q=0.4,deflate;q=0.9,compress;q=0.7');
1358         $this->assertEquals(array('deflate', 'compress', 'gzip'), $request->getEncodings());
1359     }
1360
1361     public function testGetAcceptableContentTypes()
1362     {
1363         $request = new Request();
1364         $this->assertEquals(array(), $request->getAcceptableContentTypes());
1365         $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
1366         $this->assertEquals(array(), $request->getAcceptableContentTypes()); // testing caching
1367
1368         $request = new Request();
1369         $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
1370         $this->assertEquals(array('application/vnd.wap.wmlscriptc', 'text/vnd.wap.wml', 'application/vnd.wap.xhtml+xml', 'application/xhtml+xml', 'text/html', 'multipart/mixed', '*/*'), $request->getAcceptableContentTypes());
1371     }
1372
1373     public function testGetLanguages()
1374     {
1375         $request = new Request();
1376         $this->assertEquals(array(), $request->getLanguages());
1377
1378         $request = new Request();
1379         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1380         $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
1381         $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
1382
1383         $request = new Request();
1384         $request->headers->set('Accept-language', 'zh, en-us; q=0.6, en; q=0.8');
1385         $this->assertEquals(array('zh', 'en', 'en_US'), $request->getLanguages()); // Test out of order qvalues
1386
1387         $request = new Request();
1388         $request->headers->set('Accept-language', 'zh, en, en-us');
1389         $this->assertEquals(array('zh', 'en', 'en_US'), $request->getLanguages()); // Test equal weighting without qvalues
1390
1391         $request = new Request();
1392         $request->headers->set('Accept-language', 'zh; q=0.6, en, en-us; q=0.6');
1393         $this->assertEquals(array('en', 'zh', 'en_US'), $request->getLanguages()); // Test equal weighting with qvalues
1394
1395         $request = new Request();
1396         $request->headers->set('Accept-language', 'zh, i-cherokee; q=0.6');
1397         $this->assertEquals(array('zh', 'cherokee'), $request->getLanguages());
1398     }
1399
1400     public function testGetRequestFormat()
1401     {
1402         $request = new Request();
1403         $this->assertEquals('html', $request->getRequestFormat());
1404
1405         // Ensure that setting different default values over time is possible,
1406         // aka. setRequestFormat determines the state.
1407         $this->assertEquals('json', $request->getRequestFormat('json'));
1408         $this->assertEquals('html', $request->getRequestFormat('html'));
1409
1410         $request = new Request();
1411         $this->assertNull($request->getRequestFormat(null));
1412
1413         $request = new Request();
1414         $this->assertNull($request->setRequestFormat('foo'));
1415         $this->assertEquals('foo', $request->getRequestFormat(null));
1416     }
1417
1418     public function testHasSession()
1419     {
1420         $request = new Request();
1421
1422         $this->assertFalse($request->hasSession());
1423         $request->setSession(new Session(new MockArraySessionStorage()));
1424         $this->assertTrue($request->hasSession());
1425     }
1426
1427     public function testGetSession()
1428     {
1429         $request = new Request();
1430
1431         $request->setSession(new Session(new MockArraySessionStorage()));
1432         $this->assertTrue($request->hasSession());
1433
1434         $session = $request->getSession();
1435         $this->assertObjectHasAttribute('storage', $session);
1436         $this->assertObjectHasAttribute('flashName', $session);
1437         $this->assertObjectHasAttribute('attributeName', $session);
1438     }
1439
1440     public function testHasPreviousSession()
1441     {
1442         $request = new Request();
1443
1444         $this->assertFalse($request->hasPreviousSession());
1445         $request->cookies->set('MOCKSESSID', 'foo');
1446         $this->assertFalse($request->hasPreviousSession());
1447         $request->setSession(new Session(new MockArraySessionStorage()));
1448         $this->assertTrue($request->hasPreviousSession());
1449     }
1450
1451     public function testToString()
1452     {
1453         $request = new Request();
1454
1455         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1456
1457         $this->assertContains('Accept-Language: zh, en-us; q=0.8, en; q=0.6', $request->__toString());
1458     }
1459
1460     public function testIsMethod()
1461     {
1462         $request = new Request();
1463         $request->setMethod('POST');
1464         $this->assertTrue($request->isMethod('POST'));
1465         $this->assertTrue($request->isMethod('post'));
1466         $this->assertFalse($request->isMethod('GET'));
1467         $this->assertFalse($request->isMethod('get'));
1468
1469         $request->setMethod('GET');
1470         $this->assertTrue($request->isMethod('GET'));
1471         $this->assertTrue($request->isMethod('get'));
1472         $this->assertFalse($request->isMethod('POST'));
1473         $this->assertFalse($request->isMethod('post'));
1474     }
1475
1476     /**
1477      * @dataProvider getBaseUrlData
1478      */
1479     public function testGetBaseUrl($uri, $server, $expectedBaseUrl, $expectedPathInfo)
1480     {
1481         $request = Request::create($uri, 'GET', array(), array(), array(), $server);
1482
1483         $this->assertSame($expectedBaseUrl, $request->getBaseUrl(), 'baseUrl');
1484         $this->assertSame($expectedPathInfo, $request->getPathInfo(), 'pathInfo');
1485     }
1486
1487     public function getBaseUrlData()
1488     {
1489         return array(
1490             array(
1491                 '/fruit/strawberry/1234index.php/blah',
1492                 array(
1493                     'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/fruit/index.php',
1494                     'SCRIPT_NAME' => '/fruit/index.php',
1495                     'PHP_SELF' => '/fruit/index.php',
1496                 ),
1497                 '/fruit',
1498                 '/strawberry/1234index.php/blah',
1499             ),
1500             array(
1501                 '/fruit/strawberry/1234index.php/blah',
1502                 array(
1503                     'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/index.php',
1504                     'SCRIPT_NAME' => '/index.php',
1505                     'PHP_SELF' => '/index.php',
1506                 ),
1507                 '',
1508                 '/fruit/strawberry/1234index.php/blah',
1509             ),
1510             array(
1511                 '/foo%20bar/',
1512                 array(
1513                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1514                     'SCRIPT_NAME' => '/foo bar/app.php',
1515                     'PHP_SELF' => '/foo bar/app.php',
1516                 ),
1517                 '/foo%20bar',
1518                 '/',
1519             ),
1520             array(
1521                 '/foo%20bar/home',
1522                 array(
1523                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1524                     'SCRIPT_NAME' => '/foo bar/app.php',
1525                     'PHP_SELF' => '/foo bar/app.php',
1526                 ),
1527                 '/foo%20bar',
1528                 '/home',
1529             ),
1530             array(
1531                 '/foo%20bar/app.php/home',
1532                 array(
1533                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1534                     'SCRIPT_NAME' => '/foo bar/app.php',
1535                     'PHP_SELF' => '/foo bar/app.php',
1536                 ),
1537                 '/foo%20bar/app.php',
1538                 '/home',
1539             ),
1540             array(
1541                 '/foo%20bar/app.php/home%3Dbaz',
1542                 array(
1543                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1544                     'SCRIPT_NAME' => '/foo bar/app.php',
1545                     'PHP_SELF' => '/foo bar/app.php',
1546                 ),
1547                 '/foo%20bar/app.php',
1548                 '/home%3Dbaz',
1549             ),
1550             array(
1551                 '/foo/bar+baz',
1552                 array(
1553                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo/app.php',
1554                     'SCRIPT_NAME' => '/foo/app.php',
1555                     'PHP_SELF' => '/foo/app.php',
1556                 ),
1557                 '/foo',
1558                 '/bar+baz',
1559             ),
1560         );
1561     }
1562
1563     /**
1564      * @dataProvider urlencodedStringPrefixData
1565      */
1566     public function testUrlencodedStringPrefix($string, $prefix, $expect)
1567     {
1568         $request = new Request();
1569
1570         $me = new \ReflectionMethod($request, 'getUrlencodedPrefix');
1571         $me->setAccessible(true);
1572
1573         $this->assertSame($expect, $me->invoke($request, $string, $prefix));
1574     }
1575
1576     public function urlencodedStringPrefixData()
1577     {
1578         return array(
1579             array('foo', 'foo', 'foo'),
1580             array('fo%6f', 'foo', 'fo%6f'),
1581             array('foo/bar', 'foo', 'foo'),
1582             array('fo%6f/bar', 'foo', 'fo%6f'),
1583             array('f%6f%6f/bar', 'foo', 'f%6f%6f'),
1584             array('%66%6F%6F/bar', 'foo', '%66%6F%6F'),
1585             array('fo+o/bar', 'fo+o', 'fo+o'),
1586             array('fo%2Bo/bar', 'fo+o', 'fo%2Bo'),
1587         );
1588     }
1589
1590     private function disableHttpMethodParameterOverride()
1591     {
1592         $class = new \ReflectionClass('Symfony\\Component\\HttpFoundation\\Request');
1593         $property = $class->getProperty('httpMethodParameterOverride');
1594         $property->setAccessible(true);
1595         $property->setValue(false);
1596     }
1597
1598     private function getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies)
1599     {
1600         $request = new Request();
1601
1602         $server = array('REMOTE_ADDR' => $remoteAddr);
1603         if (null !== $httpForwardedFor) {
1604             $server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
1605         }
1606
1607         if ($trustedProxies) {
1608             Request::setTrustedProxies($trustedProxies);
1609         }
1610
1611         $request->initialize(array(), array(), array(), array(), array(), $server);
1612
1613         return $request;
1614     }
1615
1616     private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies)
1617     {
1618         $request = new Request();
1619
1620         $server = array('REMOTE_ADDR' => $remoteAddr);
1621
1622         if (null !== $httpForwarded) {
1623             $server['HTTP_FORWARDED'] = $httpForwarded;
1624         }
1625
1626         if ($trustedProxies) {
1627             Request::setTrustedProxies($trustedProxies);
1628         }
1629
1630         $request->initialize(array(), array(), array(), array(), array(), $server);
1631
1632         return $request;
1633     }
1634
1635     public function testTrustedProxiesXForwardedFor()
1636     {
1637         $request = Request::create('http://example.com/');
1638         $request->server->set('REMOTE_ADDR', '3.3.3.3');
1639         $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2');
1640         $request->headers->set('X_FORWARDED_HOST', 'foo.example.com:1234, real.example.com:8080');
1641         $request->headers->set('X_FORWARDED_PROTO', 'https');
1642         $request->headers->set('X_FORWARDED_PORT', 443);
1643         $request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4');
1644         $request->headers->set('X_MY_HOST', 'my.example.com');
1645         $request->headers->set('X_MY_PROTO', 'http');
1646         $request->headers->set('X_MY_PORT', 81);
1647
1648         // no trusted proxies
1649         $this->assertEquals('3.3.3.3', $request->getClientIp());
1650         $this->assertEquals('example.com', $request->getHost());
1651         $this->assertEquals(80, $request->getPort());
1652         $this->assertFalse($request->isSecure());
1653
1654         // disabling proxy trusting
1655         Request::setTrustedProxies(array());
1656         $this->assertEquals('3.3.3.3', $request->getClientIp());
1657         $this->assertEquals('example.com', $request->getHost());
1658         $this->assertEquals(80, $request->getPort());
1659         $this->assertFalse($request->isSecure());
1660
1661         // request is forwarded by a non-trusted proxy
1662         Request::setTrustedProxies(array('2.2.2.2'));
1663         $this->assertEquals('3.3.3.3', $request->getClientIp());
1664         $this->assertEquals('example.com', $request->getHost());
1665         $this->assertEquals(80, $request->getPort());
1666         $this->assertFalse($request->isSecure());
1667
1668         // trusted proxy via setTrustedProxies()
1669         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
1670         $this->assertEquals('1.1.1.1', $request->getClientIp());
1671         $this->assertEquals('foo.example.com', $request->getHost());
1672         $this->assertEquals(443, $request->getPort());
1673         $this->assertTrue($request->isSecure());
1674
1675         // trusted proxy via setTrustedProxies()
1676         Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2'));
1677         $this->assertEquals('3.3.3.3', $request->getClientIp());
1678         $this->assertEquals('example.com', $request->getHost());
1679         $this->assertEquals(80, $request->getPort());
1680         $this->assertFalse($request->isSecure());
1681
1682         // check various X_FORWARDED_PROTO header values
1683         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
1684         $request->headers->set('X_FORWARDED_PROTO', 'ssl');
1685         $this->assertTrue($request->isSecure());
1686
1687         $request->headers->set('X_FORWARDED_PROTO', 'https, http');
1688         $this->assertTrue($request->isSecure());
1689
1690         // custom header names
1691         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR');
1692         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST');
1693         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_MY_PORT');
1694         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_MY_PROTO');
1695         $this->assertEquals('4.4.4.4', $request->getClientIp());
1696         $this->assertEquals('my.example.com', $request->getHost());
1697         $this->assertEquals(81, $request->getPort());
1698         $this->assertFalse($request->isSecure());
1699
1700         // disabling via empty header names
1701         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, null);
1702         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null);
1703         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, null);
1704         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, null);
1705         $this->assertEquals('3.3.3.3', $request->getClientIp());
1706         $this->assertEquals('example.com', $request->getHost());
1707         $this->assertEquals(80, $request->getPort());
1708         $this->assertFalse($request->isSecure());
1709
1710         // reset
1711         Request::setTrustedProxies(array());
1712         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
1713         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST');
1714         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT');
1715         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO');
1716     }
1717
1718     public function testTrustedProxiesForwarded()
1719     {
1720         $request = Request::create('http://example.com/');
1721         $request->server->set('REMOTE_ADDR', '3.3.3.3');
1722         $request->headers->set('FORWARDED', 'for=1.1.1.1, host=foo.example.com:8080, proto=https, for=2.2.2.2, host=real.example.com:8080');
1723
1724         // no trusted proxies
1725         $this->assertEquals('3.3.3.3', $request->getClientIp());
1726         $this->assertEquals('example.com', $request->getHost());
1727         $this->assertEquals(80, $request->getPort());
1728         $this->assertFalse($request->isSecure());
1729
1730         // disabling proxy trusting
1731         Request::setTrustedProxies(array());
1732         $this->assertEquals('3.3.3.3', $request->getClientIp());
1733         $this->assertEquals('example.com', $request->getHost());
1734         $this->assertEquals(80, $request->getPort());
1735         $this->assertFalse($request->isSecure());
1736
1737         // request is forwarded by a non-trusted proxy
1738         Request::setTrustedProxies(array('2.2.2.2'));
1739         $this->assertEquals('3.3.3.3', $request->getClientIp());
1740         $this->assertEquals('example.com', $request->getHost());
1741         $this->assertEquals(80, $request->getPort());
1742         $this->assertFalse($request->isSecure());
1743
1744         // trusted proxy via setTrustedProxies()
1745         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
1746         $this->assertEquals('1.1.1.1', $request->getClientIp());
1747         $this->assertEquals('foo.example.com', $request->getHost());
1748         $this->assertEquals(8080, $request->getPort());
1749         $this->assertTrue($request->isSecure());
1750
1751         // trusted proxy via setTrustedProxies()
1752         Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2'));
1753         $this->assertEquals('3.3.3.3', $request->getClientIp());
1754         $this->assertEquals('example.com', $request->getHost());
1755         $this->assertEquals(80, $request->getPort());
1756         $this->assertFalse($request->isSecure());
1757
1758         // check various X_FORWARDED_PROTO header values
1759         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
1760         $request->headers->set('FORWARDED', 'proto=ssl');
1761         $this->assertTrue($request->isSecure());
1762
1763         $request->headers->set('FORWARDED', 'proto=https, proto=http');
1764         $this->assertTrue($request->isSecure());
1765     }
1766
1767     /**
1768      * @expectedException \InvalidArgumentException
1769      */
1770     public function testSetTrustedProxiesInvalidHeaderName()
1771     {
1772         Request::create('http://example.com/');
1773         Request::setTrustedHeaderName('bogus name', 'X_MY_FOR');
1774     }
1775
1776     /**
1777      * @expectedException \InvalidArgumentException
1778      */
1779     public function testGetTrustedProxiesInvalidHeaderName()
1780     {
1781         Request::create('http://example.com/');
1782         Request::getTrustedHeaderName('bogus name');
1783     }
1784
1785     /**
1786      * @dataProvider iisRequestUriProvider
1787      */
1788     public function testIISRequestUri($headers, $server, $expectedRequestUri)
1789     {
1790         $request = new Request();
1791         $request->headers->replace($headers);
1792         $request->server->replace($server);
1793
1794         $this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct');
1795
1796         $subRequestUri = '/bar/foo';
1797         $subRequest = Request::create($subRequestUri, 'get', array(), array(), array(), $request->server->all());
1798         $this->assertEquals($subRequestUri, $subRequest->getRequestUri(), '->getRequestUri() is correct in sub request');
1799     }
1800
1801     public function iisRequestUriProvider()
1802     {
1803         return array(
1804             array(
1805                 array(
1806                     'X_ORIGINAL_URL' => '/foo/bar',
1807                 ),
1808                 array(),
1809                 '/foo/bar',
1810             ),
1811             array(
1812                 array(
1813                     'X_REWRITE_URL' => '/foo/bar',
1814                 ),
1815                 array(),
1816                 '/foo/bar',
1817             ),
1818             array(
1819                 array(),
1820                 array(
1821                     'IIS_WasUrlRewritten' => '1',
1822                     'UNENCODED_URL' => '/foo/bar',
1823                 ),
1824                 '/foo/bar',
1825             ),
1826             array(
1827                 array(
1828                     'X_ORIGINAL_URL' => '/foo/bar',
1829                 ),
1830                 array(
1831                     'HTTP_X_ORIGINAL_URL' => '/foo/bar',
1832                 ),
1833                 '/foo/bar',
1834             ),
1835             array(
1836                 array(
1837                     'X_ORIGINAL_URL' => '/foo/bar',
1838                 ),
1839                 array(
1840                     'IIS_WasUrlRewritten' => '1',
1841                     'UNENCODED_URL' => '/foo/bar',
1842                 ),
1843                 '/foo/bar',
1844             ),
1845             array(
1846                 array(
1847                     'X_ORIGINAL_URL' => '/foo/bar',
1848                 ),
1849                 array(
1850                     'HTTP_X_ORIGINAL_URL' => '/foo/bar',
1851                     'IIS_WasUrlRewritten' => '1',
1852                     'UNENCODED_URL' => '/foo/bar',
1853                 ),
1854                 '/foo/bar',
1855             ),
1856             array(
1857                 array(),
1858                 array(
1859                     'ORIG_PATH_INFO' => '/foo/bar',
1860                 ),
1861                 '/foo/bar',
1862             ),
1863             array(
1864                 array(),
1865                 array(
1866                     'ORIG_PATH_INFO' => '/foo/bar',
1867                     'QUERY_STRING' => 'foo=bar',
1868                 ),
1869                 '/foo/bar?foo=bar',
1870             ),
1871         );
1872     }
1873
1874     public function testTrustedHosts()
1875     {
1876         // create a request
1877         $request = Request::create('/');
1878
1879         // no trusted host set -> no host check
1880         $request->headers->set('host', 'evil.com');
1881         $this->assertEquals('evil.com', $request->getHost());
1882
1883         // add a trusted domain and all its subdomains
1884         Request::setTrustedHosts(array('^([a-z]{9}\.)?trusted\.com$'));
1885
1886         // untrusted host
1887         $request->headers->set('host', 'evil.com');
1888         try {
1889             $request->getHost();
1890             $this->fail('Request::getHost() should throw an exception when host is not trusted.');
1891         } catch (\UnexpectedValueException $e) {
1892             $this->assertEquals('Untrusted Host "evil.com"', $e->getMessage());
1893         }
1894
1895         // trusted hosts
1896         $request->headers->set('host', 'trusted.com');
1897         $this->assertEquals('trusted.com', $request->getHost());
1898         $this->assertEquals(80, $request->getPort());
1899
1900         $request->server->set('HTTPS', true);
1901         $request->headers->set('host', 'trusted.com');
1902         $this->assertEquals('trusted.com', $request->getHost());
1903         $this->assertEquals(443, $request->getPort());
1904         $request->server->set('HTTPS', false);
1905
1906         $request->headers->set('host', 'trusted.com:8000');
1907         $this->assertEquals('trusted.com', $request->getHost());
1908         $this->assertEquals(8000, $request->getPort());
1909
1910         $request->headers->set('host', 'subdomain.trusted.com');
1911         $this->assertEquals('subdomain.trusted.com', $request->getHost());
1912
1913         // reset request for following tests
1914         Request::setTrustedHosts(array());
1915     }
1916
1917     public function testFactory()
1918     {
1919         Request::setFactory(function (array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) {
1920             return new NewRequest();
1921         });
1922
1923         $this->assertEquals('foo', Request::create('/')->getFoo());
1924
1925         Request::setFactory(null);
1926     }
1927
1928     /**
1929      * @dataProvider getLongHostNames
1930      */
1931     public function testVeryLongHosts($host)
1932     {
1933         $start = microtime(true);
1934
1935         $request = Request::create('/');
1936         $request->headers->set('host', $host);
1937         $this->assertEquals($host, $request->getHost());
1938         $this->assertLessThan(5, microtime(true) - $start);
1939     }
1940
1941     /**
1942      * @dataProvider getHostValidities
1943      */
1944     public function testHostValidity($host, $isValid, $expectedHost = null, $expectedPort = null)
1945     {
1946         $request = Request::create('/');
1947         $request->headers->set('host', $host);
1948
1949         if ($isValid) {
1950             $this->assertSame($expectedHost ?: $host, $request->getHost());
1951             if ($expectedPort) {
1952                 $this->assertSame($expectedPort, $request->getPort());
1953             }
1954         } else {
1955             if (method_exists($this, 'expectException')) {
1956                 $this->expectException('UnexpectedValueException');
1957                 $this->expectExceptionMessage('Invalid Host');
1958             } else {
1959                 $this->setExpectedException('UnexpectedValueException', 'Invalid Host');
1960             }
1961
1962             $request->getHost();
1963         }
1964     }
1965
1966     public function getHostValidities()
1967     {
1968         return array(
1969             array('.a', false),
1970             array('a..', false),
1971             array('a.', true),
1972             array("\xE9", false),
1973             array('[::1]', true),
1974             array('[::1]:80', true, '[::1]', 80),
1975             array(str_repeat('.', 101), false),
1976         );
1977     }
1978
1979     public function getLongHostNames()
1980     {
1981         return array(
1982             array('a'.str_repeat('.a', 40000)),
1983             array(str_repeat(':', 101)),
1984         );
1985     }
1986
1987     /**
1988      * @dataProvider methodSafeProvider
1989      */
1990     public function testMethodSafe($method, $safe)
1991     {
1992         $request = new Request();
1993         $request->setMethod($method);
1994         $this->assertEquals($safe, $request->isMethodSafe(false));
1995     }
1996
1997     public function methodSafeProvider()
1998     {
1999         return array(
2000             array('HEAD', true),
2001             array('GET', true),
2002             array('POST', false),
2003             array('PUT', false),
2004             array('PATCH', false),
2005             array('DELETE', false),
2006             array('PURGE', false),
2007             array('OPTIONS', true),
2008             array('TRACE', true),
2009             array('CONNECT', false),
2010         );
2011     }
2012
2013     public function testMethodSafeChecksCacheable()
2014     {
2015         $request = new Request();
2016         $request->setMethod('OPTIONS');
2017         $this->assertFalse($request->isMethodSafe());
2018     }
2019
2020     /**
2021      * @dataProvider methodCacheableProvider
2022      */
2023     public function testMethodCacheable($method, $chacheable)
2024     {
2025         $request = new Request();
2026         $request->setMethod($method);
2027         $this->assertEquals($chacheable, $request->isMethodCacheable());
2028     }
2029
2030     public function methodCacheableProvider()
2031     {
2032         return array(
2033             array('HEAD', true),
2034             array('GET', true),
2035             array('POST', false),
2036             array('PUT', false),
2037             array('PATCH', false),
2038             array('DELETE', false),
2039             array('PURGE', false),
2040             array('OPTIONS', false),
2041             array('TRACE', false),
2042             array('CONNECT', false),
2043         );
2044     }
2045
2046     public function nonstandardRequestsData()
2047     {
2048         return array(
2049             array('',  '', '/', 'http://host:8080/', ''),
2050             array('/', '', '/', 'http://host:8080/', ''),
2051
2052             array('hello/app.php/x',  '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'),
2053             array('/hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'),
2054
2055             array('',      'a=b', '/', 'http://host:8080/?a=b'),
2056             array('?a=b',  'a=b', '/', 'http://host:8080/?a=b'),
2057             array('/?a=b', 'a=b', '/', 'http://host:8080/?a=b'),
2058
2059             array('x',      'a=b', '/x', 'http://host:8080/x?a=b'),
2060             array('x?a=b',  'a=b', '/x', 'http://host:8080/x?a=b'),
2061             array('/x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'),
2062
2063             array('hello/x',  '', '/x', 'http://host:8080/hello/x', '/hello'),
2064             array('/hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'),
2065
2066             array('hello/app.php/x',      'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2067             array('hello/app.php/x?a=b',  'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2068             array('/hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2069         );
2070     }
2071
2072     /**
2073      * @dataProvider nonstandardRequestsData
2074      */
2075     public function testNonstandardRequests($requestUri, $queryString, $expectedPathInfo, $expectedUri, $expectedBasePath = '', $expectedBaseUrl = null)
2076     {
2077         if (null === $expectedBaseUrl) {
2078             $expectedBaseUrl = $expectedBasePath;
2079         }
2080
2081         $server = array(
2082             'HTTP_HOST' => 'host:8080',
2083             'SERVER_PORT' => '8080',
2084             'QUERY_STRING' => $queryString,
2085             'PHP_SELF' => '/hello/app.php',
2086             'SCRIPT_FILENAME' => '/some/path/app.php',
2087             'REQUEST_URI' => $requestUri,
2088         );
2089
2090         $request = new Request(array(), array(), array(), array(), array(), $server);
2091
2092         $this->assertEquals($expectedPathInfo, $request->getPathInfo());
2093         $this->assertEquals($expectedUri, $request->getUri());
2094         $this->assertEquals($queryString, $request->getQueryString());
2095         $this->assertEquals(8080, $request->getPort());
2096         $this->assertEquals('host:8080', $request->getHttpHost());
2097         $this->assertEquals($expectedBaseUrl, $request->getBaseUrl());
2098         $this->assertEquals($expectedBasePath, $request->getBasePath());
2099     }
2100 }
2101
2102 class RequestContentProxy extends Request
2103 {
2104     public function getContent($asResource = false)
2105     {
2106         return http_build_query(array('_method' => 'PUT', 'content' => 'mycontent'));
2107     }
2108 }
2109
2110 class NewRequest extends Request
2111 {
2112     public function getFoo()
2113     {
2114         return 'foo';
2115     }
2116 }