230ad156738e8ffc4eacf4bbe8df70133cffb073
[yaffs-website] / vendor / symfony / http-foundation / Tests / RequestTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpFoundation\Tests;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
16 use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
17 use Symfony\Component\HttpFoundation\Session\Session;
18 use Symfony\Component\HttpFoundation\Request;
19
20 class RequestTest extends TestCase
21 {
22     protected function tearDown()
23     {
24         // reset
25         Request::setTrustedProxies(array(), -1);
26     }
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
853     /**
854      * @dataProvider getClientIpsProvider
855      */
856     public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
857     {
858         $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies);
859
860         $this->assertEquals($expected[0], $request->getClientIp());
861     }
862
863     /**
864      * @dataProvider getClientIpsProvider
865      */
866     public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
867     {
868         $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies);
869
870         $this->assertEquals($expected, $request->getClientIps());
871     }
872
873     /**
874      * @dataProvider getClientIpsForwardedProvider
875      */
876     public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies)
877     {
878         $request = $this->getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies);
879
880         $this->assertEquals($expected, $request->getClientIps());
881     }
882
883     public function getClientIpsForwardedProvider()
884     {
885         //              $expected                                  $remoteAddr  $httpForwarded                                       $trustedProxies
886         return array(
887             array(array('127.0.0.1'),                              '127.0.0.1', 'for="_gazonk"',                                      null),
888             array(array('127.0.0.1'),                              '127.0.0.1', 'for="_gazonk"',                                      array('127.0.0.1')),
889             array(array('88.88.88.88'),                            '127.0.0.1', 'for="88.88.88.88:80"',                               array('127.0.0.1')),
890             array(array('192.0.2.60'),                             '::1',       'for=192.0.2.60;proto=http;by=203.0.113.43',          array('::1')),
891             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')),
892             array(array('2001:db8:cafe::17'),                      '::1',       'for="[2001:db8:cafe::17]:4711',                      array('::1')),
893         );
894     }
895
896     public function getClientIpsProvider()
897     {
898         //        $expected                   $remoteAddr                $httpForwardedFor            $trustedProxies
899         return array(
900             // simple IPv4
901             array(array('88.88.88.88'),              '88.88.88.88',              null,                        null),
902             // trust the IPv4 remote addr
903             array(array('88.88.88.88'),              '88.88.88.88',              null,                        array('88.88.88.88')),
904
905             // simple IPv6
906             array(array('::1'),                      '::1',                      null,                        null),
907             // trust the IPv6 remote addr
908             array(array('::1'),                      '::1',                      null,                        array('::1')),
909
910             // forwarded for with remote IPv4 addr not trusted
911             array(array('127.0.0.1'),                '127.0.0.1',                '88.88.88.88',               null),
912             // forwarded for with remote IPv4 addr trusted
913             array(array('88.88.88.88'),              '127.0.0.1',                '88.88.88.88',               array('127.0.0.1')),
914             // forwarded for with remote IPv4 and all FF addrs trusted
915             array(array('88.88.88.88'),              '127.0.0.1',                '88.88.88.88',               array('127.0.0.1', '88.88.88.88')),
916             // forwarded for with remote IPv4 range trusted
917             array(array('88.88.88.88'),              '123.45.67.89',             '88.88.88.88',               array('123.45.67.0/24')),
918
919             // forwarded for with remote IPv6 addr not trusted
920             array(array('1620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3',  null),
921             // forwarded for with remote IPv6 addr trusted
922             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')),
923             // forwarded for with remote IPv6 range trusted
924             array(array('88.88.88.88'),              '2a01:198:603:0:396e:4789:8e99:890f', '88.88.88.88',     array('2a01:198:603:0::/65')),
925
926             // multiple forwarded for with remote IPv4 addr trusted
927             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')),
928             // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted
929             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')),
930             // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle
931             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')),
932             // multiple forwarded for with remote IPv4 addr and all reverse proxies trusted
933             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')),
934
935             // multiple forwarded for with remote IPv6 addr trusted
936             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')),
937             // multiple forwarded for with remote IPv6 addr and some reverse proxies trusted
938             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')),
939             // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle
940             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')),
941
942             // client IP with port
943             array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88:12345, 127.0.0.1', array('127.0.0.1')),
944
945             // invalid forwarded IP is ignored
946             array(array('88.88.88.88'), '127.0.0.1', 'unknown,88.88.88.88', array('127.0.0.1')),
947             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')),
948         );
949     }
950
951     /**
952      * @expectedException \Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException
953      * @dataProvider getClientIpsWithConflictingHeadersProvider
954      */
955     public function testGetClientIpsWithConflictingHeaders($httpForwarded, $httpXForwardedFor)
956     {
957         $request = new Request();
958
959         $server = array(
960             'REMOTE_ADDR' => '88.88.88.88',
961             'HTTP_FORWARDED' => $httpForwarded,
962             'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
963         );
964
965         Request::setTrustedProxies(array('88.88.88.88'), Request::HEADER_X_FORWARDED_ALL | Request::HEADER_FORWARDED);
966
967         $request->initialize(array(), array(), array(), array(), array(), $server);
968
969         $request->getClientIps();
970     }
971
972     /**
973      * @dataProvider getClientIpsWithConflictingHeadersProvider
974      */
975     public function testGetClientIpsOnlyXHttpForwardedForTrusted($httpForwarded, $httpXForwardedFor)
976     {
977         $request = new Request();
978
979         $server = array(
980             'REMOTE_ADDR' => '88.88.88.88',
981             'HTTP_FORWARDED' => $httpForwarded,
982             'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
983         );
984
985         Request::setTrustedProxies(array('88.88.88.88'), Request::HEADER_X_FORWARDED_FOR);
986
987         $request->initialize(array(), array(), array(), array(), array(), $server);
988
989         $this->assertSame(array_reverse(explode(',', $httpXForwardedFor)), $request->getClientIps());
990     }
991
992     public function getClientIpsWithConflictingHeadersProvider()
993     {
994         //        $httpForwarded                   $httpXForwardedFor
995         return array(
996             array('for=87.65.43.21',                 '192.0.2.60'),
997             array('for=87.65.43.21, for=192.0.2.60', '192.0.2.60'),
998             array('for=192.0.2.60',                  '192.0.2.60,87.65.43.21'),
999             array('for="::face", for=192.0.2.60',    '192.0.2.60,192.0.2.43'),
1000             array('for=87.65.43.21, for=192.0.2.60', '192.0.2.60,87.65.43.21'),
1001         );
1002     }
1003
1004     /**
1005      * @dataProvider getClientIpsWithAgreeingHeadersProvider
1006      */
1007     public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwardedFor, $expectedIps)
1008     {
1009         $request = new Request();
1010
1011         $server = array(
1012             'REMOTE_ADDR' => '88.88.88.88',
1013             'HTTP_FORWARDED' => $httpForwarded,
1014             'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
1015         );
1016
1017         Request::setTrustedProxies(array('88.88.88.88'), Request::HEADER_X_FORWARDED_ALL);
1018
1019         $request->initialize(array(), array(), array(), array(), array(), $server);
1020
1021         $clientIps = $request->getClientIps();
1022
1023         $this->assertSame($expectedIps, $clientIps);
1024     }
1025
1026     public function getClientIpsWithAgreeingHeadersProvider()
1027     {
1028         //        $httpForwarded                               $httpXForwardedFor
1029         return array(
1030             array('for="192.0.2.60"',                          '192.0.2.60',             array('192.0.2.60')),
1031             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')),
1032             array('for="[::face]", for=192.0.2.60',            '::face,192.0.2.60',      array('192.0.2.60', '::face')),
1033             array('for="192.0.2.60:80"',                       '192.0.2.60',             array('192.0.2.60')),
1034             array('for=192.0.2.60;proto=http;by=203.0.113.43', '192.0.2.60',             array('192.0.2.60')),
1035             array('for="[2001:db8:cafe::17]:4711"',            '2001:db8:cafe::17',      array('2001:db8:cafe::17')),
1036         );
1037     }
1038
1039     public function testGetContentWorksTwiceInDefaultMode()
1040     {
1041         $req = new Request();
1042         $this->assertEquals('', $req->getContent());
1043         $this->assertEquals('', $req->getContent());
1044     }
1045
1046     public function testGetContentReturnsResource()
1047     {
1048         $req = new Request();
1049         $retval = $req->getContent(true);
1050         $this->assertInternalType('resource', $retval);
1051         $this->assertEquals('', fread($retval, 1));
1052         $this->assertTrue(feof($retval));
1053     }
1054
1055     public function testGetContentReturnsResourceWhenContentSetInConstructor()
1056     {
1057         $req = new Request(array(), array(), array(), array(), array(), array(), 'MyContent');
1058         $resource = $req->getContent(true);
1059
1060         $this->assertInternalType('resource', $resource);
1061         $this->assertEquals('MyContent', stream_get_contents($resource));
1062     }
1063
1064     public function testContentAsResource()
1065     {
1066         $resource = fopen('php://memory', 'r+');
1067         fwrite($resource, 'My other content');
1068         rewind($resource);
1069
1070         $req = new Request(array(), array(), array(), array(), array(), array(), $resource);
1071         $this->assertEquals('My other content', stream_get_contents($req->getContent(true)));
1072         $this->assertEquals('My other content', $req->getContent());
1073     }
1074
1075     /**
1076      * @expectedException \LogicException
1077      * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
1078      */
1079     public function testGetContentCantBeCalledTwiceWithResources($first, $second)
1080     {
1081         if (\PHP_VERSION_ID >= 50600) {
1082             $this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.');
1083         }
1084
1085         $req = new Request();
1086         $req->getContent($first);
1087         $req->getContent($second);
1088     }
1089
1090     public function getContentCantBeCalledTwiceWithResourcesProvider()
1091     {
1092         return array(
1093             'Resource then fetch' => array(true, false),
1094             'Resource then resource' => array(true, true),
1095         );
1096     }
1097
1098     /**
1099      * @dataProvider getContentCanBeCalledTwiceWithResourcesProvider
1100      * @requires PHP 5.6
1101      */
1102     public function testGetContentCanBeCalledTwiceWithResources($first, $second)
1103     {
1104         $req = new Request();
1105         $a = $req->getContent($first);
1106         $b = $req->getContent($second);
1107
1108         if ($first) {
1109             $a = stream_get_contents($a);
1110         }
1111
1112         if ($second) {
1113             $b = stream_get_contents($b);
1114         }
1115
1116         $this->assertSame($a, $b);
1117     }
1118
1119     public function getContentCanBeCalledTwiceWithResourcesProvider()
1120     {
1121         return array(
1122             'Fetch then fetch' => array(false, false),
1123             'Fetch then resource' => array(false, true),
1124             'Resource then fetch' => array(true, false),
1125             'Resource then resource' => array(true, true),
1126         );
1127     }
1128
1129     public function provideOverloadedMethods()
1130     {
1131         return array(
1132             array('PUT'),
1133             array('DELETE'),
1134             array('PATCH'),
1135             array('put'),
1136             array('delete'),
1137             array('patch'),
1138         );
1139     }
1140
1141     /**
1142      * @dataProvider provideOverloadedMethods
1143      */
1144     public function testCreateFromGlobals($method)
1145     {
1146         $normalizedMethod = strtoupper($method);
1147
1148         $_GET['foo1'] = 'bar1';
1149         $_POST['foo2'] = 'bar2';
1150         $_COOKIE['foo3'] = 'bar3';
1151         $_FILES['foo4'] = array('bar4');
1152         $_SERVER['foo5'] = 'bar5';
1153
1154         $request = Request::createFromGlobals();
1155         $this->assertEquals('bar1', $request->query->get('foo1'), '::fromGlobals() uses values from $_GET');
1156         $this->assertEquals('bar2', $request->request->get('foo2'), '::fromGlobals() uses values from $_POST');
1157         $this->assertEquals('bar3', $request->cookies->get('foo3'), '::fromGlobals() uses values from $_COOKIE');
1158         $this->assertEquals(array('bar4'), $request->files->get('foo4'), '::fromGlobals() uses values from $_FILES');
1159         $this->assertEquals('bar5', $request->server->get('foo5'), '::fromGlobals() uses values from $_SERVER');
1160
1161         unset($_GET['foo1'], $_POST['foo2'], $_COOKIE['foo3'], $_FILES['foo4'], $_SERVER['foo5']);
1162
1163         $_SERVER['REQUEST_METHOD'] = $method;
1164         $_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
1165         $request = RequestContentProxy::createFromGlobals();
1166         $this->assertEquals($normalizedMethod, $request->getMethod());
1167         $this->assertEquals('mycontent', $request->request->get('content'));
1168
1169         unset($_SERVER['REQUEST_METHOD'], $_SERVER['CONTENT_TYPE']);
1170
1171         Request::createFromGlobals();
1172         Request::enableHttpMethodParameterOverride();
1173         $_POST['_method'] = $method;
1174         $_POST['foo6'] = 'bar6';
1175         $_SERVER['REQUEST_METHOD'] = 'PoSt';
1176         $request = Request::createFromGlobals();
1177         $this->assertEquals($normalizedMethod, $request->getMethod());
1178         $this->assertEquals('POST', $request->getRealMethod());
1179         $this->assertEquals('bar6', $request->request->get('foo6'));
1180
1181         unset($_POST['_method'], $_POST['foo6'], $_SERVER['REQUEST_METHOD']);
1182         $this->disableHttpMethodParameterOverride();
1183     }
1184
1185     public function testOverrideGlobals()
1186     {
1187         $request = new Request();
1188         $request->initialize(array('foo' => 'bar'));
1189
1190         // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it
1191         $server = $_SERVER;
1192
1193         $request->overrideGlobals();
1194
1195         $this->assertEquals(array('foo' => 'bar'), $_GET);
1196
1197         $request->initialize(array(), array('foo' => 'bar'));
1198         $request->overrideGlobals();
1199
1200         $this->assertEquals(array('foo' => 'bar'), $_POST);
1201
1202         $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
1203
1204         $request->headers->set('X_FORWARDED_PROTO', 'https');
1205
1206         Request::setTrustedProxies(array('1.1.1.1'), Request::HEADER_X_FORWARDED_ALL);
1207         $this->assertFalse($request->isSecure());
1208         $request->server->set('REMOTE_ADDR', '1.1.1.1');
1209         $this->assertTrue($request->isSecure());
1210
1211         $request->overrideGlobals();
1212
1213         $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
1214
1215         $request->headers->set('CONTENT_TYPE', 'multipart/form-data');
1216         $request->headers->set('CONTENT_LENGTH', 12345);
1217
1218         $request->overrideGlobals();
1219
1220         $this->assertArrayHasKey('CONTENT_TYPE', $_SERVER);
1221         $this->assertArrayHasKey('CONTENT_LENGTH', $_SERVER);
1222
1223         $request->initialize(array('foo' => 'bar', 'baz' => 'foo'));
1224         $request->query->remove('baz');
1225
1226         $request->overrideGlobals();
1227
1228         $this->assertEquals(array('foo' => 'bar'), $_GET);
1229         $this->assertEquals('foo=bar', $_SERVER['QUERY_STRING']);
1230         $this->assertEquals('foo=bar', $request->server->get('QUERY_STRING'));
1231
1232         // restore initial $_SERVER array
1233         $_SERVER = $server;
1234     }
1235
1236     public function testGetScriptName()
1237     {
1238         $request = new Request();
1239         $this->assertEquals('', $request->getScriptName());
1240
1241         $server = array();
1242         $server['SCRIPT_NAME'] = '/index.php';
1243
1244         $request->initialize(array(), array(), array(), array(), array(), $server);
1245
1246         $this->assertEquals('/index.php', $request->getScriptName());
1247
1248         $server = array();
1249         $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
1250         $request->initialize(array(), array(), array(), array(), array(), $server);
1251
1252         $this->assertEquals('/frontend.php', $request->getScriptName());
1253
1254         $server = array();
1255         $server['SCRIPT_NAME'] = '/index.php';
1256         $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
1257         $request->initialize(array(), array(), array(), array(), array(), $server);
1258
1259         $this->assertEquals('/index.php', $request->getScriptName());
1260     }
1261
1262     public function testGetBasePath()
1263     {
1264         $request = new Request();
1265         $this->assertEquals('', $request->getBasePath());
1266
1267         $server = array();
1268         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1269         $request->initialize(array(), array(), array(), array(), array(), $server);
1270         $this->assertEquals('', $request->getBasePath());
1271
1272         $server = array();
1273         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1274         $server['SCRIPT_NAME'] = '/index.php';
1275         $request->initialize(array(), array(), array(), array(), array(), $server);
1276
1277         $this->assertEquals('', $request->getBasePath());
1278
1279         $server = array();
1280         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1281         $server['PHP_SELF'] = '/index.php';
1282         $request->initialize(array(), array(), array(), array(), array(), $server);
1283
1284         $this->assertEquals('', $request->getBasePath());
1285
1286         $server = array();
1287         $server['SCRIPT_FILENAME'] = '/some/where/index.php';
1288         $server['ORIG_SCRIPT_NAME'] = '/index.php';
1289         $request->initialize(array(), array(), array(), array(), array(), $server);
1290
1291         $this->assertEquals('', $request->getBasePath());
1292     }
1293
1294     public function testGetPathInfo()
1295     {
1296         $request = new Request();
1297         $this->assertEquals('/', $request->getPathInfo());
1298
1299         $server = array();
1300         $server['REQUEST_URI'] = '/path/info';
1301         $request->initialize(array(), array(), array(), array(), array(), $server);
1302
1303         $this->assertEquals('/path/info', $request->getPathInfo());
1304
1305         $server = array();
1306         $server['REQUEST_URI'] = '/path%20test/info';
1307         $request->initialize(array(), array(), array(), array(), array(), $server);
1308
1309         $this->assertEquals('/path%20test/info', $request->getPathInfo());
1310
1311         $server = array();
1312         $server['REQUEST_URI'] = '?a=b';
1313         $request->initialize(array(), array(), array(), array(), array(), $server);
1314
1315         $this->assertEquals('/', $request->getPathInfo());
1316     }
1317
1318     public function testGetParameterPrecedence()
1319     {
1320         $request = new Request();
1321         $request->attributes->set('foo', 'attr');
1322         $request->query->set('foo', 'query');
1323         $request->request->set('foo', 'body');
1324
1325         $this->assertSame('attr', $request->get('foo'));
1326
1327         $request->attributes->remove('foo');
1328         $this->assertSame('query', $request->get('foo'));
1329
1330         $request->query->remove('foo');
1331         $this->assertSame('body', $request->get('foo'));
1332
1333         $request->request->remove('foo');
1334         $this->assertNull($request->get('foo'));
1335     }
1336
1337     public function testGetPreferredLanguage()
1338     {
1339         $request = new Request();
1340         $this->assertNull($request->getPreferredLanguage());
1341         $this->assertNull($request->getPreferredLanguage(array()));
1342         $this->assertEquals('fr', $request->getPreferredLanguage(array('fr')));
1343         $this->assertEquals('fr', $request->getPreferredLanguage(array('fr', 'en')));
1344         $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'fr')));
1345         $this->assertEquals('fr-ch', $request->getPreferredLanguage(array('fr-ch', 'fr-fr')));
1346
1347         $request = new Request();
1348         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1349         $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'en-us')));
1350
1351         $request = new Request();
1352         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1353         $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
1354
1355         $request = new Request();
1356         $request->headers->set('Accept-language', 'zh, en-us; q=0.8');
1357         $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
1358
1359         $request = new Request();
1360         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, fr-fr; q=0.6, fr; q=0.5');
1361         $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
1362     }
1363
1364     public function testIsXmlHttpRequest()
1365     {
1366         $request = new Request();
1367         $this->assertFalse($request->isXmlHttpRequest());
1368
1369         $request->headers->set('X-Requested-With', 'XMLHttpRequest');
1370         $this->assertTrue($request->isXmlHttpRequest());
1371
1372         $request->headers->remove('X-Requested-With');
1373         $this->assertFalse($request->isXmlHttpRequest());
1374     }
1375
1376     /**
1377      * @requires extension intl
1378      */
1379     public function testIntlLocale()
1380     {
1381         $request = new Request();
1382
1383         $request->setDefaultLocale('fr');
1384         $this->assertEquals('fr', $request->getLocale());
1385         $this->assertEquals('fr', \Locale::getDefault());
1386
1387         $request->setLocale('en');
1388         $this->assertEquals('en', $request->getLocale());
1389         $this->assertEquals('en', \Locale::getDefault());
1390
1391         $request->setDefaultLocale('de');
1392         $this->assertEquals('en', $request->getLocale());
1393         $this->assertEquals('en', \Locale::getDefault());
1394     }
1395
1396     public function testGetCharsets()
1397     {
1398         $request = new Request();
1399         $this->assertEquals(array(), $request->getCharsets());
1400         $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
1401         $this->assertEquals(array(), $request->getCharsets()); // testing caching
1402
1403         $request = new Request();
1404         $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
1405         $this->assertEquals(array('ISO-8859-1', 'US-ASCII', 'UTF-8', 'ISO-10646-UCS-2'), $request->getCharsets());
1406
1407         $request = new Request();
1408         $request->headers->set('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7');
1409         $this->assertEquals(array('ISO-8859-1', 'utf-8', '*'), $request->getCharsets());
1410     }
1411
1412     public function testGetEncodings()
1413     {
1414         $request = new Request();
1415         $this->assertEquals(array(), $request->getEncodings());
1416         $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch');
1417         $this->assertEquals(array(), $request->getEncodings()); // testing caching
1418
1419         $request = new Request();
1420         $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch');
1421         $this->assertEquals(array('gzip', 'deflate', 'sdch'), $request->getEncodings());
1422
1423         $request = new Request();
1424         $request->headers->set('Accept-Encoding', 'gzip;q=0.4,deflate;q=0.9,compress;q=0.7');
1425         $this->assertEquals(array('deflate', 'compress', 'gzip'), $request->getEncodings());
1426     }
1427
1428     public function testGetAcceptableContentTypes()
1429     {
1430         $request = new Request();
1431         $this->assertEquals(array(), $request->getAcceptableContentTypes());
1432         $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
1433         $this->assertEquals(array(), $request->getAcceptableContentTypes()); // testing caching
1434
1435         $request = new Request();
1436         $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
1437         $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());
1438     }
1439
1440     public function testGetLanguages()
1441     {
1442         $request = new Request();
1443         $this->assertEquals(array(), $request->getLanguages());
1444
1445         $request = new Request();
1446         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1447         $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
1448         $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
1449
1450         $request = new Request();
1451         $request->headers->set('Accept-language', 'zh, en-us; q=0.6, en; q=0.8');
1452         $this->assertEquals(array('zh', 'en', 'en_US'), $request->getLanguages()); // Test out of order qvalues
1453
1454         $request = new Request();
1455         $request->headers->set('Accept-language', 'zh, en, en-us');
1456         $this->assertEquals(array('zh', 'en', 'en_US'), $request->getLanguages()); // Test equal weighting without qvalues
1457
1458         $request = new Request();
1459         $request->headers->set('Accept-language', 'zh; q=0.6, en, en-us; q=0.6');
1460         $this->assertEquals(array('en', 'zh', 'en_US'), $request->getLanguages()); // Test equal weighting with qvalues
1461
1462         $request = new Request();
1463         $request->headers->set('Accept-language', 'zh, i-cherokee; q=0.6');
1464         $this->assertEquals(array('zh', 'cherokee'), $request->getLanguages());
1465     }
1466
1467     public function testGetRequestFormat()
1468     {
1469         $request = new Request();
1470         $this->assertEquals('html', $request->getRequestFormat());
1471
1472         // Ensure that setting different default values over time is possible,
1473         // aka. setRequestFormat determines the state.
1474         $this->assertEquals('json', $request->getRequestFormat('json'));
1475         $this->assertEquals('html', $request->getRequestFormat('html'));
1476
1477         $request = new Request();
1478         $this->assertNull($request->getRequestFormat(null));
1479
1480         $request = new Request();
1481         $this->assertNull($request->setRequestFormat('foo'));
1482         $this->assertEquals('foo', $request->getRequestFormat(null));
1483
1484         $request = new Request(array('_format' => 'foo'));
1485         $this->assertEquals('html', $request->getRequestFormat());
1486     }
1487
1488     public function testHasSession()
1489     {
1490         $request = new Request();
1491
1492         $this->assertFalse($request->hasSession());
1493         $request->setSession(new Session(new MockArraySessionStorage()));
1494         $this->assertTrue($request->hasSession());
1495     }
1496
1497     public function testGetSession()
1498     {
1499         $request = new Request();
1500
1501         $request->setSession(new Session(new MockArraySessionStorage()));
1502         $this->assertTrue($request->hasSession());
1503
1504         $session = $request->getSession();
1505         $this->assertObjectHasAttribute('storage', $session);
1506         $this->assertObjectHasAttribute('flashName', $session);
1507         $this->assertObjectHasAttribute('attributeName', $session);
1508     }
1509
1510     public function testHasPreviousSession()
1511     {
1512         $request = new Request();
1513
1514         $this->assertFalse($request->hasPreviousSession());
1515         $request->cookies->set('MOCKSESSID', 'foo');
1516         $this->assertFalse($request->hasPreviousSession());
1517         $request->setSession(new Session(new MockArraySessionStorage()));
1518         $this->assertTrue($request->hasPreviousSession());
1519     }
1520
1521     public function testToString()
1522     {
1523         $request = new Request();
1524
1525         $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
1526         $request->cookies->set('Foo', 'Bar');
1527
1528         $asString = (string) $request;
1529
1530         $this->assertContains('Accept-Language: zh, en-us; q=0.8, en; q=0.6', $asString);
1531         $this->assertContains('Cookie: Foo=Bar', $asString);
1532
1533         $request->cookies->set('Another', 'Cookie');
1534
1535         $asString = (string) $request;
1536
1537         $this->assertContains('Cookie: Foo=Bar; Another=Cookie', $asString);
1538     }
1539
1540     public function testIsMethod()
1541     {
1542         $request = new Request();
1543         $request->setMethod('POST');
1544         $this->assertTrue($request->isMethod('POST'));
1545         $this->assertTrue($request->isMethod('post'));
1546         $this->assertFalse($request->isMethod('GET'));
1547         $this->assertFalse($request->isMethod('get'));
1548
1549         $request->setMethod('GET');
1550         $this->assertTrue($request->isMethod('GET'));
1551         $this->assertTrue($request->isMethod('get'));
1552         $this->assertFalse($request->isMethod('POST'));
1553         $this->assertFalse($request->isMethod('post'));
1554     }
1555
1556     /**
1557      * @dataProvider getBaseUrlData
1558      */
1559     public function testGetBaseUrl($uri, $server, $expectedBaseUrl, $expectedPathInfo)
1560     {
1561         $request = Request::create($uri, 'GET', array(), array(), array(), $server);
1562
1563         $this->assertSame($expectedBaseUrl, $request->getBaseUrl(), 'baseUrl');
1564         $this->assertSame($expectedPathInfo, $request->getPathInfo(), 'pathInfo');
1565     }
1566
1567     public function getBaseUrlData()
1568     {
1569         return array(
1570             array(
1571                 '/fruit/strawberry/1234index.php/blah',
1572                 array(
1573                     'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/fruit/index.php',
1574                     'SCRIPT_NAME' => '/fruit/index.php',
1575                     'PHP_SELF' => '/fruit/index.php',
1576                 ),
1577                 '/fruit',
1578                 '/strawberry/1234index.php/blah',
1579             ),
1580             array(
1581                 '/fruit/strawberry/1234index.php/blah',
1582                 array(
1583                     'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/index.php',
1584                     'SCRIPT_NAME' => '/index.php',
1585                     'PHP_SELF' => '/index.php',
1586                 ),
1587                 '',
1588                 '/fruit/strawberry/1234index.php/blah',
1589             ),
1590             array(
1591                 '/foo%20bar/',
1592                 array(
1593                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1594                     'SCRIPT_NAME' => '/foo bar/app.php',
1595                     'PHP_SELF' => '/foo bar/app.php',
1596                 ),
1597                 '/foo%20bar',
1598                 '/',
1599             ),
1600             array(
1601                 '/foo%20bar/home',
1602                 array(
1603                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1604                     'SCRIPT_NAME' => '/foo bar/app.php',
1605                     'PHP_SELF' => '/foo bar/app.php',
1606                 ),
1607                 '/foo%20bar',
1608                 '/home',
1609             ),
1610             array(
1611                 '/foo%20bar/app.php/home',
1612                 array(
1613                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1614                     'SCRIPT_NAME' => '/foo bar/app.php',
1615                     'PHP_SELF' => '/foo bar/app.php',
1616                 ),
1617                 '/foo%20bar/app.php',
1618                 '/home',
1619             ),
1620             array(
1621                 '/foo%20bar/app.php/home%3Dbaz',
1622                 array(
1623                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
1624                     'SCRIPT_NAME' => '/foo bar/app.php',
1625                     'PHP_SELF' => '/foo bar/app.php',
1626                 ),
1627                 '/foo%20bar/app.php',
1628                 '/home%3Dbaz',
1629             ),
1630             array(
1631                 '/foo/bar+baz',
1632                 array(
1633                     'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo/app.php',
1634                     'SCRIPT_NAME' => '/foo/app.php',
1635                     'PHP_SELF' => '/foo/app.php',
1636                 ),
1637                 '/foo',
1638                 '/bar+baz',
1639             ),
1640         );
1641     }
1642
1643     /**
1644      * @dataProvider urlencodedStringPrefixData
1645      */
1646     public function testUrlencodedStringPrefix($string, $prefix, $expect)
1647     {
1648         $request = new Request();
1649
1650         $me = new \ReflectionMethod($request, 'getUrlencodedPrefix');
1651         $me->setAccessible(true);
1652
1653         $this->assertSame($expect, $me->invoke($request, $string, $prefix));
1654     }
1655
1656     public function urlencodedStringPrefixData()
1657     {
1658         return array(
1659             array('foo', 'foo', 'foo'),
1660             array('fo%6f', 'foo', 'fo%6f'),
1661             array('foo/bar', 'foo', 'foo'),
1662             array('fo%6f/bar', 'foo', 'fo%6f'),
1663             array('f%6f%6f/bar', 'foo', 'f%6f%6f'),
1664             array('%66%6F%6F/bar', 'foo', '%66%6F%6F'),
1665             array('fo+o/bar', 'fo+o', 'fo+o'),
1666             array('fo%2Bo/bar', 'fo+o', 'fo%2Bo'),
1667         );
1668     }
1669
1670     private function disableHttpMethodParameterOverride()
1671     {
1672         $class = new \ReflectionClass('Symfony\\Component\\HttpFoundation\\Request');
1673         $property = $class->getProperty('httpMethodParameterOverride');
1674         $property->setAccessible(true);
1675         $property->setValue(false);
1676     }
1677
1678     private function getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies)
1679     {
1680         $request = new Request();
1681
1682         $server = array('REMOTE_ADDR' => $remoteAddr);
1683         if (null !== $httpForwardedFor) {
1684             $server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
1685         }
1686
1687         if ($trustedProxies) {
1688             Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_ALL);
1689         }
1690
1691         $request->initialize(array(), array(), array(), array(), array(), $server);
1692
1693         return $request;
1694     }
1695
1696     private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies)
1697     {
1698         $request = new Request();
1699
1700         $server = array('REMOTE_ADDR' => $remoteAddr);
1701
1702         if (null !== $httpForwarded) {
1703             $server['HTTP_FORWARDED'] = $httpForwarded;
1704         }
1705
1706         if ($trustedProxies) {
1707             Request::setTrustedProxies($trustedProxies, Request::HEADER_FORWARDED);
1708         }
1709
1710         $request->initialize(array(), array(), array(), array(), array(), $server);
1711
1712         return $request;
1713     }
1714
1715     public function testTrustedProxiesXForwardedFor()
1716     {
1717         $request = Request::create('http://example.com/');
1718         $request->server->set('REMOTE_ADDR', '3.3.3.3');
1719         $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2');
1720         $request->headers->set('X_FORWARDED_HOST', 'foo.example.com:1234, real.example.com:8080');
1721         $request->headers->set('X_FORWARDED_PROTO', 'https');
1722         $request->headers->set('X_FORWARDED_PORT', 443);
1723
1724         // no trusted proxies
1725         $this->assertEquals('3.3.3.3', $request->getClientIp());
1726         $this->assertEquals('example.com', $request->getHost());
1727         $this->assertEquals(80, $request->getPort());
1728         $this->assertFalse($request->isSecure());
1729
1730         // disabling proxy trusting
1731         Request::setTrustedProxies(array(), Request::HEADER_X_FORWARDED_ALL);
1732         $this->assertEquals('3.3.3.3', $request->getClientIp());
1733         $this->assertEquals('example.com', $request->getHost());
1734         $this->assertEquals(80, $request->getPort());
1735         $this->assertFalse($request->isSecure());
1736
1737         // request is forwarded by a non-trusted proxy
1738         Request::setTrustedProxies(array('2.2.2.2'), Request::HEADER_X_FORWARDED_ALL);
1739         $this->assertEquals('3.3.3.3', $request->getClientIp());
1740         $this->assertEquals('example.com', $request->getHost());
1741         $this->assertEquals(80, $request->getPort());
1742         $this->assertFalse($request->isSecure());
1743
1744         // trusted proxy via setTrustedProxies()
1745         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_X_FORWARDED_ALL);
1746         $this->assertEquals('1.1.1.1', $request->getClientIp());
1747         $this->assertEquals('foo.example.com', $request->getHost());
1748         $this->assertEquals(443, $request->getPort());
1749         $this->assertTrue($request->isSecure());
1750
1751         // trusted proxy via setTrustedProxies()
1752         Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2'), Request::HEADER_X_FORWARDED_ALL);
1753         $this->assertEquals('3.3.3.3', $request->getClientIp());
1754         $this->assertEquals('example.com', $request->getHost());
1755         $this->assertEquals(80, $request->getPort());
1756         $this->assertFalse($request->isSecure());
1757
1758         // check various X_FORWARDED_PROTO header values
1759         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_X_FORWARDED_ALL);
1760         $request->headers->set('X_FORWARDED_PROTO', 'ssl');
1761         $this->assertTrue($request->isSecure());
1762
1763         $request->headers->set('X_FORWARDED_PROTO', 'https, http');
1764         $this->assertTrue($request->isSecure());
1765     }
1766
1767     /**
1768      * @group legacy
1769      * @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.
1770      */
1771     public function testLegacyTrustedProxies()
1772     {
1773         $request = Request::create('http://example.com/');
1774         $request->server->set('REMOTE_ADDR', '3.3.3.3');
1775         $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2');
1776         $request->headers->set('X_FORWARDED_HOST', 'foo.example.com, real.example.com:8080');
1777         $request->headers->set('X_FORWARDED_PROTO', 'https');
1778         $request->headers->set('X_FORWARDED_PORT', 443);
1779         $request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4');
1780         $request->headers->set('X_MY_HOST', 'my.example.com');
1781         $request->headers->set('X_MY_PROTO', 'http');
1782         $request->headers->set('X_MY_PORT', 81);
1783
1784         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_X_FORWARDED_ALL);
1785
1786         // custom header names
1787         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR');
1788         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST');
1789         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_MY_PORT');
1790         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_MY_PROTO');
1791         $this->assertEquals('4.4.4.4', $request->getClientIp());
1792         $this->assertEquals('my.example.com', $request->getHost());
1793         $this->assertEquals(81, $request->getPort());
1794         $this->assertFalse($request->isSecure());
1795
1796         // disabling via empty header names
1797         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, null);
1798         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null);
1799         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, null);
1800         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, null);
1801         $this->assertEquals('3.3.3.3', $request->getClientIp());
1802         $this->assertEquals('example.com', $request->getHost());
1803         $this->assertEquals(80, $request->getPort());
1804         $this->assertFalse($request->isSecure());
1805
1806         //reset
1807         Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED');
1808         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
1809         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST');
1810         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT');
1811         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO');
1812     }
1813
1814     public function testTrustedProxiesForwarded()
1815     {
1816         $request = Request::create('http://example.com/');
1817         $request->server->set('REMOTE_ADDR', '3.3.3.3');
1818         $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');
1819
1820         // no trusted proxies
1821         $this->assertEquals('3.3.3.3', $request->getClientIp());
1822         $this->assertEquals('example.com', $request->getHost());
1823         $this->assertEquals(80, $request->getPort());
1824         $this->assertFalse($request->isSecure());
1825
1826         // disabling proxy trusting
1827         Request::setTrustedProxies(array(), Request::HEADER_FORWARDED);
1828         $this->assertEquals('3.3.3.3', $request->getClientIp());
1829         $this->assertEquals('example.com', $request->getHost());
1830         $this->assertEquals(80, $request->getPort());
1831         $this->assertFalse($request->isSecure());
1832
1833         // request is forwarded by a non-trusted proxy
1834         Request::setTrustedProxies(array('2.2.2.2'), Request::HEADER_FORWARDED);
1835         $this->assertEquals('3.3.3.3', $request->getClientIp());
1836         $this->assertEquals('example.com', $request->getHost());
1837         $this->assertEquals(80, $request->getPort());
1838         $this->assertFalse($request->isSecure());
1839
1840         // trusted proxy via setTrustedProxies()
1841         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_FORWARDED);
1842         $this->assertEquals('1.1.1.1', $request->getClientIp());
1843         $this->assertEquals('foo.example.com', $request->getHost());
1844         $this->assertEquals(8080, $request->getPort());
1845         $this->assertTrue($request->isSecure());
1846
1847         // trusted proxy via setTrustedProxies()
1848         Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2'), Request::HEADER_FORWARDED);
1849         $this->assertEquals('3.3.3.3', $request->getClientIp());
1850         $this->assertEquals('example.com', $request->getHost());
1851         $this->assertEquals(80, $request->getPort());
1852         $this->assertFalse($request->isSecure());
1853
1854         // check various X_FORWARDED_PROTO header values
1855         Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_FORWARDED);
1856         $request->headers->set('FORWARDED', 'proto=ssl');
1857         $this->assertTrue($request->isSecure());
1858
1859         $request->headers->set('FORWARDED', 'proto=https, proto=http');
1860         $this->assertTrue($request->isSecure());
1861     }
1862
1863     /**
1864      * @group legacy
1865      * @expectedException \InvalidArgumentException
1866      */
1867     public function testSetTrustedProxiesInvalidHeaderName()
1868     {
1869         Request::create('http://example.com/');
1870         Request::setTrustedHeaderName('bogus name', 'X_MY_FOR');
1871     }
1872
1873     /**
1874      * @group legacy
1875      * @expectedException \InvalidArgumentException
1876      */
1877     public function testGetTrustedProxiesInvalidHeaderName()
1878     {
1879         Request::create('http://example.com/');
1880         Request::getTrustedHeaderName('bogus name');
1881     }
1882
1883     /**
1884      * @dataProvider iisRequestUriProvider
1885      */
1886     public function testIISRequestUri($headers, $server, $expectedRequestUri)
1887     {
1888         $request = new Request();
1889         $request->headers->replace($headers);
1890         $request->server->replace($server);
1891
1892         $this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct');
1893
1894         $subRequestUri = '/bar/foo';
1895         $subRequest = Request::create($subRequestUri, 'get', array(), array(), array(), $request->server->all());
1896         $this->assertEquals($subRequestUri, $subRequest->getRequestUri(), '->getRequestUri() is correct in sub request');
1897     }
1898
1899     public function iisRequestUriProvider()
1900     {
1901         return array(
1902             array(
1903                 array(
1904                     'X_ORIGINAL_URL' => '/foo/bar',
1905                 ),
1906                 array(),
1907                 '/foo/bar',
1908             ),
1909             array(
1910                 array(
1911                     'X_REWRITE_URL' => '/foo/bar',
1912                 ),
1913                 array(),
1914                 '/foo/bar',
1915             ),
1916             array(
1917                 array(),
1918                 array(
1919                     'IIS_WasUrlRewritten' => '1',
1920                     'UNENCODED_URL' => '/foo/bar',
1921                 ),
1922                 '/foo/bar',
1923             ),
1924             array(
1925                 array(
1926                     'X_ORIGINAL_URL' => '/foo/bar',
1927                 ),
1928                 array(
1929                     'HTTP_X_ORIGINAL_URL' => '/foo/bar',
1930                 ),
1931                 '/foo/bar',
1932             ),
1933             array(
1934                 array(
1935                     'X_ORIGINAL_URL' => '/foo/bar',
1936                 ),
1937                 array(
1938                     'IIS_WasUrlRewritten' => '1',
1939                     'UNENCODED_URL' => '/foo/bar',
1940                 ),
1941                 '/foo/bar',
1942             ),
1943             array(
1944                 array(
1945                     'X_ORIGINAL_URL' => '/foo/bar',
1946                 ),
1947                 array(
1948                     'HTTP_X_ORIGINAL_URL' => '/foo/bar',
1949                     'IIS_WasUrlRewritten' => '1',
1950                     'UNENCODED_URL' => '/foo/bar',
1951                 ),
1952                 '/foo/bar',
1953             ),
1954             array(
1955                 array(),
1956                 array(
1957                     'ORIG_PATH_INFO' => '/foo/bar',
1958                 ),
1959                 '/foo/bar',
1960             ),
1961             array(
1962                 array(),
1963                 array(
1964                     'ORIG_PATH_INFO' => '/foo/bar',
1965                     'QUERY_STRING' => 'foo=bar',
1966                 ),
1967                 '/foo/bar?foo=bar',
1968             ),
1969         );
1970     }
1971
1972     public function testTrustedHosts()
1973     {
1974         // create a request
1975         $request = Request::create('/');
1976
1977         // no trusted host set -> no host check
1978         $request->headers->set('host', 'evil.com');
1979         $this->assertEquals('evil.com', $request->getHost());
1980
1981         // add a trusted domain and all its subdomains
1982         Request::setTrustedHosts(array('^([a-z]{9}\.)?trusted\.com$'));
1983
1984         // untrusted host
1985         $request->headers->set('host', 'evil.com');
1986         try {
1987             $request->getHost();
1988             $this->fail('Request::getHost() should throw an exception when host is not trusted.');
1989         } catch (SuspiciousOperationException $e) {
1990             $this->assertEquals('Untrusted Host "evil.com".', $e->getMessage());
1991         }
1992
1993         // trusted hosts
1994         $request->headers->set('host', 'trusted.com');
1995         $this->assertEquals('trusted.com', $request->getHost());
1996         $this->assertEquals(80, $request->getPort());
1997
1998         $request->server->set('HTTPS', true);
1999         $request->headers->set('host', 'trusted.com');
2000         $this->assertEquals('trusted.com', $request->getHost());
2001         $this->assertEquals(443, $request->getPort());
2002         $request->server->set('HTTPS', false);
2003
2004         $request->headers->set('host', 'trusted.com:8000');
2005         $this->assertEquals('trusted.com', $request->getHost());
2006         $this->assertEquals(8000, $request->getPort());
2007
2008         $request->headers->set('host', 'subdomain.trusted.com');
2009         $this->assertEquals('subdomain.trusted.com', $request->getHost());
2010
2011         // reset request for following tests
2012         Request::setTrustedHosts(array());
2013     }
2014
2015     public function testFactory()
2016     {
2017         Request::setFactory(function (array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) {
2018             return new NewRequest();
2019         });
2020
2021         $this->assertEquals('foo', Request::create('/')->getFoo());
2022
2023         Request::setFactory(null);
2024     }
2025
2026     /**
2027      * @dataProvider getLongHostNames
2028      */
2029     public function testVeryLongHosts($host)
2030     {
2031         $start = microtime(true);
2032
2033         $request = Request::create('/');
2034         $request->headers->set('host', $host);
2035         $this->assertEquals($host, $request->getHost());
2036         $this->assertLessThan(5, microtime(true) - $start);
2037     }
2038
2039     /**
2040      * @dataProvider getHostValidities
2041      */
2042     public function testHostValidity($host, $isValid, $expectedHost = null, $expectedPort = null)
2043     {
2044         $request = Request::create('/');
2045         $request->headers->set('host', $host);
2046
2047         if ($isValid) {
2048             $this->assertSame($expectedHost ?: $host, $request->getHost());
2049             if ($expectedPort) {
2050                 $this->assertSame($expectedPort, $request->getPort());
2051             }
2052         } else {
2053             if (method_exists($this, 'expectException')) {
2054                 $this->expectException(SuspiciousOperationException::class);
2055                 $this->expectExceptionMessage('Invalid Host');
2056             } else {
2057                 $this->setExpectedException(SuspiciousOperationException::class, 'Invalid Host');
2058             }
2059
2060             $request->getHost();
2061         }
2062     }
2063
2064     public function getHostValidities()
2065     {
2066         return array(
2067             array('.a', false),
2068             array('a..', false),
2069             array('a.', true),
2070             array("\xE9", false),
2071             array('[::1]', true),
2072             array('[::1]:80', true, '[::1]', 80),
2073             array(str_repeat('.', 101), false),
2074         );
2075     }
2076
2077     public function getLongHostNames()
2078     {
2079         return array(
2080             array('a'.str_repeat('.a', 40000)),
2081             array(str_repeat(':', 101)),
2082         );
2083     }
2084
2085     /**
2086      * @dataProvider methodIdempotentProvider
2087      */
2088     public function testMethodIdempotent($method, $idempotent)
2089     {
2090         $request = new Request();
2091         $request->setMethod($method);
2092         $this->assertEquals($idempotent, $request->isMethodIdempotent());
2093     }
2094
2095     public function methodIdempotentProvider()
2096     {
2097         return array(
2098             array('HEAD', true),
2099             array('GET', true),
2100             array('POST', false),
2101             array('PUT', true),
2102             array('PATCH', false),
2103             array('DELETE', true),
2104             array('PURGE', true),
2105             array('OPTIONS', true),
2106             array('TRACE', true),
2107             array('CONNECT', false),
2108         );
2109     }
2110
2111     /**
2112      * @dataProvider methodSafeProvider
2113      */
2114     public function testMethodSafe($method, $safe)
2115     {
2116         $request = new Request();
2117         $request->setMethod($method);
2118         $this->assertEquals($safe, $request->isMethodSafe(false));
2119     }
2120
2121     public function methodSafeProvider()
2122     {
2123         return array(
2124             array('HEAD', true),
2125             array('GET', true),
2126             array('POST', false),
2127             array('PUT', false),
2128             array('PATCH', false),
2129             array('DELETE', false),
2130             array('PURGE', false),
2131             array('OPTIONS', true),
2132             array('TRACE', true),
2133             array('CONNECT', false),
2134         );
2135     }
2136
2137     /**
2138      * @group legacy
2139      * @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.
2140      */
2141     public function testMethodSafeChecksCacheable()
2142     {
2143         $request = new Request();
2144         $request->setMethod('OPTIONS');
2145         $this->assertFalse($request->isMethodSafe());
2146     }
2147
2148     /**
2149      * @dataProvider methodCacheableProvider
2150      */
2151     public function testMethodCacheable($method, $cacheable)
2152     {
2153         $request = new Request();
2154         $request->setMethod($method);
2155         $this->assertEquals($cacheable, $request->isMethodCacheable());
2156     }
2157
2158     public function methodCacheableProvider()
2159     {
2160         return array(
2161             array('HEAD', true),
2162             array('GET', true),
2163             array('POST', false),
2164             array('PUT', false),
2165             array('PATCH', false),
2166             array('DELETE', false),
2167             array('PURGE', false),
2168             array('OPTIONS', false),
2169             array('TRACE', false),
2170             array('CONNECT', false),
2171         );
2172     }
2173
2174     /**
2175      * @group legacy
2176      */
2177     public function testGetTrustedHeaderName()
2178     {
2179         Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_X_FORWARDED_ALL);
2180
2181         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
2182         $this->assertSame('X_FORWARDED_FOR', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
2183         $this->assertSame('X_FORWARDED_HOST', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
2184         $this->assertSame('X_FORWARDED_PORT', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
2185         $this->assertSame('X_FORWARDED_PROTO', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
2186
2187         Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED);
2188
2189         $this->assertSame('FORWARDED', Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
2190         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
2191         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
2192         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
2193         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
2194
2195         Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'A');
2196         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'B');
2197         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'C');
2198         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'D');
2199         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'E');
2200
2201         Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED);
2202
2203         $this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
2204         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
2205         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
2206         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
2207         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
2208
2209         Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_X_FORWARDED_ALL);
2210
2211         $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
2212         $this->assertSame('B', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
2213         $this->assertSame('C', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
2214         $this->assertSame('D', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
2215         $this->assertSame('E', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
2216
2217         Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED);
2218
2219         $this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
2220
2221         //reset
2222         Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED');
2223         Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
2224         Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST');
2225         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT');
2226         Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO');
2227     }
2228
2229     /**
2230      * @dataProvider protocolVersionProvider
2231      */
2232     public function testProtocolVersion($serverProtocol, $trustedProxy, $via, $expected)
2233     {
2234         if ($trustedProxy) {
2235             Request::setTrustedProxies(array('1.1.1.1'), -1);
2236         }
2237
2238         $request = new Request();
2239         $request->server->set('SERVER_PROTOCOL', $serverProtocol);
2240         $request->server->set('REMOTE_ADDR', '1.1.1.1');
2241         $request->headers->set('Via', $via);
2242
2243         $this->assertSame($expected, $request->getProtocolVersion());
2244     }
2245
2246     public function protocolVersionProvider()
2247     {
2248         return array(
2249             'untrusted without via' => array('HTTP/2.0', false, '', 'HTTP/2.0'),
2250             'untrusted with via' => array('HTTP/2.0', false, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/2.0'),
2251             'trusted without via' => array('HTTP/2.0', true, '', 'HTTP/2.0'),
2252             'trusted with via' => array('HTTP/2.0', true, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'),
2253             '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'),
2254             'trusted with broken via' => array('HTTP/2.0', true, 'HTTP/1^0 foo', 'HTTP/2.0'),
2255             'trusted with partially-broken via' => array('HTTP/2.0', true, '1.0 fred, foo', 'HTTP/1.0'),
2256         );
2257     }
2258
2259     public function nonstandardRequestsData()
2260     {
2261         return array(
2262             array('',  '', '/', 'http://host:8080/', ''),
2263             array('/', '', '/', 'http://host:8080/', ''),
2264
2265             array('hello/app.php/x',  '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'),
2266             array('/hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'),
2267
2268             array('',      'a=b', '/', 'http://host:8080/?a=b'),
2269             array('?a=b',  'a=b', '/', 'http://host:8080/?a=b'),
2270             array('/?a=b', 'a=b', '/', 'http://host:8080/?a=b'),
2271
2272             array('x',      'a=b', '/x', 'http://host:8080/x?a=b'),
2273             array('x?a=b',  'a=b', '/x', 'http://host:8080/x?a=b'),
2274             array('/x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'),
2275
2276             array('hello/x',  '', '/x', 'http://host:8080/hello/x', '/hello'),
2277             array('/hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'),
2278
2279             array('hello/app.php/x',      'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2280             array('hello/app.php/x?a=b',  'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2281             array('/hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'),
2282         );
2283     }
2284
2285     /**
2286      * @dataProvider nonstandardRequestsData
2287      */
2288     public function testNonstandardRequests($requestUri, $queryString, $expectedPathInfo, $expectedUri, $expectedBasePath = '', $expectedBaseUrl = null)
2289     {
2290         if (null === $expectedBaseUrl) {
2291             $expectedBaseUrl = $expectedBasePath;
2292         }
2293
2294         $server = array(
2295             'HTTP_HOST' => 'host:8080',
2296             'SERVER_PORT' => '8080',
2297             'QUERY_STRING' => $queryString,
2298             'PHP_SELF' => '/hello/app.php',
2299             'SCRIPT_FILENAME' => '/some/path/app.php',
2300             'REQUEST_URI' => $requestUri,
2301         );
2302
2303         $request = new Request(array(), array(), array(), array(), array(), $server);
2304
2305         $this->assertEquals($expectedPathInfo, $request->getPathInfo());
2306         $this->assertEquals($expectedUri, $request->getUri());
2307         $this->assertEquals($queryString, $request->getQueryString());
2308         $this->assertEquals(8080, $request->getPort());
2309         $this->assertEquals('host:8080', $request->getHttpHost());
2310         $this->assertEquals($expectedBaseUrl, $request->getBaseUrl());
2311         $this->assertEquals($expectedBasePath, $request->getBasePath());
2312     }
2313 }
2314
2315 class RequestContentProxy extends Request
2316 {
2317     public function getContent($asResource = false)
2318     {
2319         return http_build_query(array('_method' => 'PUT', 'content' => 'mycontent'), '', '&');
2320     }
2321 }
2322
2323 class NewRequest extends Request
2324 {
2325     public function getFoo()
2326     {
2327         return 'foo';
2328     }
2329 }