Skip to content

Commit aacfe74

Browse files
committed
merged branch fabpot/http-method-override (PR symfony#6143)
This PR was merged into the master branch. Commits ------- 0a380cf [HttpFoundation] disabled Request _method feature by default (should now be explicitely enabled via a call to enableHttpMethodOverride()) Discussion ---------- [HttpFoundation] disabled Request _method feature by default It should now be explicitely enabled via a call to enableHttpMethodOverride())
2 parents 13b47b6 + 0a380cf commit aacfe74

File tree

4 files changed

+74
-3
lines changed

4 files changed

+74
-3
lines changed

UPGRADE-2.2.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
* The Stopwatch functionality was moved from HttpKernel\Debug to its own component
1414

15+
* The _method request parameter support has been disabled by default (call
16+
Request::enableHttpMethodParameterOverride() to enable it).
17+
1518
#### Deprecations
1619

1720
* The `Request::splitHttpAcceptHeader()` is deprecated and will be removed in 2.3.

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
2.2.0
55
-----
66

7+
* added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
8+
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it)
79
* Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
810

911
2.1.0

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class Request
3232
{
3333
protected static $trustProxy = false;
3434

35+
protected static $httpMethodParameterOverride = false;
36+
3537
/**
3638
* @var \Symfony\Component\HttpFoundation\ParameterBag
3739
*
@@ -503,6 +505,19 @@ public static function normalizeQueryString($qs)
503505
return implode('&', $parts);
504506
}
505507

508+
/**
509+
* Enables support for the _method request parameter to determine the intended HTTP method.
510+
*
511+
* Be warned that enabling this feature might lead to CSRF issues in your code.
512+
* Check that you are using CSRF tokens when required.
513+
*
514+
* The HTTP method can only be overriden when the real HTTP method is POST.
515+
*/
516+
public static function enableHttpMethodParameterOverride()
517+
{
518+
self::$httpMethodParameterOverride = true;
519+
}
520+
506521
/**
507522
* Gets a "parameter" value.
508523
*
@@ -915,26 +930,51 @@ public function setMethod($method)
915930
}
916931

917932
/**
918-
* Gets the request method.
933+
* Gets the request "intended" method.
934+
*
935+
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
936+
* then it is used to determine the "real" intended HTTP method.
937+
*
938+
* The _method request parameter can also be used to determine the HTTP method,
939+
* but only if enableHttpMethodParameterOverride() has been called.
919940
*
920941
* The method is always an uppercased string.
921942
*
922943
* @return string The request method
923944
*
924945
* @api
946+
*
947+
* @see getRealMethod
925948
*/
926949
public function getMethod()
927950
{
928951
if (null === $this->method) {
929952
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
953+
930954
if ('POST' === $this->method) {
931-
$this->method = strtoupper($this->headers->get('X-HTTP-METHOD-OVERRIDE', $this->request->get('_method', $this->query->get('_method', 'POST'))));
955+
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
956+
$this->method = strtoupper($method);
957+
} elseif (self::$httpMethodParameterOverride) {
958+
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
959+
}
932960
}
933961
}
934962

935963
return $this->method;
936964
}
937965

966+
/**
967+
* Gets the "real" request method.
968+
*
969+
* @return string The request method
970+
*
971+
* @see getMethod
972+
*/
973+
public function getRealMethod()
974+
{
975+
return $this->server->get('REQUEST_METHOD', 'GET');
976+
}
977+
938978
/**
939979
* Gets the mime type associated with the format.
940980
*

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,13 +675,28 @@ public function testGetSetMethod()
675675

676676
$request->setMethod('POST');
677677
$request->request->set('_method', 'purge');
678+
$this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled');
679+
680+
$request = new Request();
681+
$request->setMethod('POST');
682+
$request->request->set('_method', 'purge');
683+
Request::enableHttpMethodParameterOverride();
678684
$this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
685+
$this->disableHttpMethodParameterOverride();
679686

687+
$request = new Request();
688+
$request->setMethod('POST');
689+
$request->query->set('_method', 'purge');
690+
$this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled');
691+
692+
$request = new Request();
680693
$request->setMethod('POST');
681-
$request->request->remove('_method');
682694
$request->query->set('_method', 'purge');
695+
Request::enableHttpMethodParameterOverride();
683696
$this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
697+
$this->disableHttpMethodParameterOverride();
684698

699+
$request = new Request();
685700
$request->setMethod('POST');
686701
$request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
687702
$this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override even though _method is set if defined and POST');
@@ -807,6 +822,8 @@ public function testCreateFromGlobals($method)
807822

808823
unset($_SERVER['REQUEST_METHOD'], $_SERVER['CONTENT_TYPE']);
809824

825+
$request = Request::createFromGlobals();
826+
Request::enableHttpMethodParameterOverride();
810827
$_POST['_method'] = $method;
811828
$_POST['foo6'] = 'bar6';
812829
$_SERVER['REQUEST_METHOD'] = 'POST';
@@ -815,6 +832,7 @@ public function testCreateFromGlobals($method)
815832
$this->assertEquals('bar6', $request->request->get('foo6'));
816833

817834
unset($_POST['_method'], $_POST['foo6'], $_SERVER['REQUEST_METHOD']);
835+
$this->disableHttpMethodParameterOverride();
818836
}
819837

820838
public function testOverrideGlobals()
@@ -1254,6 +1272,14 @@ private function stopTrustingProxyData()
12541272
$property->setAccessible(true);
12551273
$property->setValue(false);
12561274
}
1275+
1276+
private function disableHttpMethodParameterOverride()
1277+
{
1278+
$class = new \ReflectionClass('Symfony\\Component\\HttpFoundation\\Request');
1279+
$property = $class->getProperty('httpMethodParameterOverride');
1280+
$property->setAccessible(true);
1281+
$property->setValue(false);
1282+
}
12571283
}
12581284

12591285
class RequestContentProxy extends Request

0 commit comments

Comments
 (0)