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