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