Issue #2147153 by dawehner, alexpott, Xano: Replace the last instance of $_GET/$_POST; Create a special exception listener / exception controller which allows to use POST requests.

8.0.x
Nathaniel Catchpole 2014-02-10 10:38:41 +00:00
parent 91db25eba4
commit e4e83f0e95
8 changed files with 170 additions and 9 deletions

View File

@ -111,7 +111,7 @@ services:
class: Drupal\Core\Form\FormBuilder class: Drupal\Core\Form\FormBuilder
arguments: ['@module_handler', '@keyvalue.expirable', '@event_dispatcher', '@url_generator', '@string_translation', '@?csrf_token', '@?http_kernel'] arguments: ['@module_handler', '@keyvalue.expirable', '@event_dispatcher', '@url_generator', '@string_translation', '@?csrf_token', '@?http_kernel']
calls: calls:
- [setRequest, ['@?request']] - [setRequest, ['@?request=']]
keyvalue: keyvalue:
class: Drupal\Core\KeyValueStore\KeyValueFactory class: Drupal\Core\KeyValueStore\KeyValueFactory
arguments: ['@service_container', '@settings'] arguments: ['@service_container', '@settings']
@ -218,6 +218,7 @@ services:
request: request:
class: Symfony\Component\HttpFoundation\Request class: Symfony\Component\HttpFoundation\Request
synthetic: true synthetic: true
synchronized: true
request_stack: request_stack:
class: Symfony\Component\HttpFoundation\RequestStack class: Symfony\Component\HttpFoundation\RequestStack
event_dispatcher: event_dispatcher:
@ -546,7 +547,7 @@ services:
calls: calls:
- [setContainer, ['@service_container']] - [setContainer, ['@service_container']]
exception_listener: exception_listener:
class: Symfony\Component\HttpKernel\EventListener\ExceptionListener class: Drupal\Core\EventSubscriber\ExceptionListener
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
arguments: [['@exception_controller', execute]] arguments: [['@exception_controller', execute]]

View File

@ -146,7 +146,13 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn
$request->query->set('destination', $system_path); $request->query->set('destination', $system_path);
} }
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'get', array('destination' => $system_path, '_exception_statuscode' => 403), $request->cookies->all(), array(), $request->server->all()); if ($request->getMethod() === 'POST') {
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'POST', array('destination' => $system_path, '_exception_statuscode' => 403) + $request->request->all(), $request->cookies->all(), array(), $request->server->all());
$subrequest->query->set('destination', $system_path);
}
else {
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 403), $request->cookies->all(), array(), $request->server->all());
}
// The active trail is being statically cached from the parent request to // The active trail is being statically cached from the parent request to
// the subrequest, like any other static. Unfortunately that means the // the subrequest, like any other static. Unfortunately that means the
@ -223,7 +229,13 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn
// @todo The create() method expects a slash-prefixed path, but we store a // @todo The create() method expects a slash-prefixed path, but we store a
// normal system path in the site_404 variable. // normal system path in the site_404 variable.
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'get', array('destination' => $system_path, '_exception_statuscode' => 403), $request->cookies->all(), array(), $request->server->all()); if ($request->getMethod() === 'POST') {
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'POST', array('destination' => $system_path, '_exception_statuscode' => 404) + $request->request->all(), $request->cookies->all(), array(), $request->server->all());
$subrequest->query->set('destination', $system_path);
}
else {
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 404), $request->cookies->all(), array(), $request->server->all());
}
// The active trail is being statically cached from the parent request to // The active trail is being statically cached from the parent request to
// the subrequest, like any other static. Unfortunately that means the // the subrequest, like any other static. Unfortunately that means the

View File

@ -0,0 +1,36 @@
<?php
/**
* @file
* Contains \Drupal\Core\EventSubscriber\ExceptionListener.
*/
namespace Drupal\Core\EventSubscriber;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\EventListener\ExceptionListener as ExceptionListenerBase;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
/**
* Extends the symfony exception listener to support POST subrequests.
*/
class ExceptionListener extends ExceptionListenerBase {
/**
* {@inheritdoc}
*
* In contrast to the symfony base class, do not override POST requests to GET
* requests.
*/
protected function duplicateRequest(\Exception $exception, Request $request) {
$attributes = array(
'_controller' => $this->controller,
'exception' => FlattenException::create($exception),
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : NULL,
'format' => $request->getRequestFormat(),
);
return $request->duplicate(NULL, NULL, $attributes);
}
}

View File

@ -200,7 +200,7 @@ class FormBuilder implements FormBuilderInterface {
$form_id = $this->getFormId($form_id, $form_state); $form_id = $this->getFormId($form_id, $form_state);
if (!isset($form_state['input'])) { if (!isset($form_state['input'])) {
$form_state['input'] = $form_state['method'] == 'get' ? $_GET : $_POST; $form_state['input'] = $form_state['method'] == 'get' ? $this->request->query->all() : $this->request->request->all();
} }
if (isset($_SESSION['batch_form_state'])) { if (isset($_SESSION['batch_form_state'])) {

View File

@ -67,7 +67,7 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
function setUp() { function setUp() {
parent::setUp(); parent::setUp();
$this->request = Request::create('http://example.com/'); $this->request = Request::createFromGlobals();
$this->container->set('request', $this->request); $this->container->set('request', $this->request);
$admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks')); $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks'));

View File

@ -33,7 +33,7 @@ class SessionHttpsTest extends WebTestBase {
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
$this->request = Request::create('http://example.com/'); $this->request = Request::createFromGlobals();
$this->container->set('request', $this->request); $this->container->set('request', $this->request);
} }

View File

@ -35,8 +35,7 @@ class FloodTest extends WebTestBase {
// Flood backends need a request object. Create a dummy one and insert it // Flood backends need a request object. Create a dummy one and insert it
// to the container. // to the container.
$this->request = Request::create('http://example.com/'); $this->request = Request::createFromGlobals();
$this->request->server->set('REMOTE_ADDR', '3.3.3.3');
$this->container->set('request', $this->request); $this->container->set('request', $this->request);
} }

View File

@ -0,0 +1,113 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\EventSubscriber\ExceptionListenerTest.
*/
namespace Drupal\Tests\Core\EventSubscriber;
use Drupal\Component\Utility\Url;
use Drupal\Core\EventSubscriber\ExceptionListener;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
/**
* Tests the exception listener.
*
* @group Drupal
* @group Routing
*
* @see \Drupal\Core\EventSubscriber\ExceptionListener
*/
class ExceptionListenerTest extends UnitTestCase {
/**
* The tested exception listener.
*
* @var \Drupal\Core\EventSubscriber\ExceptionListener
*/
protected $exceptionListener;
/**
* The mocked HTTP kernel.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $kernel;
/**
* The PHP error log settings before the test.
*
* @var string
*/
protected $errorLog;
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Exception listener',
'description' => 'Tests the exception listener',
'group' => 'Routing',
);
}
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->exceptionListener = new ExceptionListener('example');
$this->kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
// You can't create an exception in PHP without throwing it. Store the
// current error_log, and disable it temporarily.
$this->errorLog = ini_set('error_log', file_exists('/dev/null') ? '/dev/null' : 'nul');
}
/**
* {@inheritdoc}
*/
protected function tearDown() {
ini_set('error_log', $this->errorLog);
}
/**
* Tests onHandleException with a POST request.
*/
public function testHandleWithPostRequest() {
$request = Request::create('/test', 'POST', array('name' => 'druplicon', 'pass' => '12345'));
$this->kernel->expects($this->once())->method('handle')->will($this->returnCallback(function (Request $request) {
return new Response($request->getMethod());
}));
$event = new GetResponseForExceptionEvent($this->kernel, $request, 'foo', new \Exception('foo'));
$this->exceptionListener->onKernelException($event);
$response = $event->getResponse();
$this->assertEquals('POST name=druplicon&pass=12345', $response->getContent() . " " . Url::buildQuery($request->request->all()));
}
/**
* Tests onHandleException with a GET request.
*/
public function testHandleWithGetRequest() {
$request = Request::create('/test', 'GET', array('name' => 'druplicon', 'pass' => '12345'));
$this->kernel->expects($this->once())->method('handle')->will($this->returnCallback(function (Request $request) {
return new Response($request->getMethod() . ' ' . Url::buildQuery($request->query->all()));
}));
$event = new GetResponseForExceptionEvent($this->kernel, $request, 'foo', new \Exception('foo'));
$this->exceptionListener->onKernelException($event);
$response = $event->getResponse();
$this->assertEquals('GET name=druplicon&pass=12345 ', $response->getContent() . " " . Url::buildQuery($request->request->all()));
}
}