Issue #2536052 by znerol, jungle, Rishi Kulshreshtha, smustgrave, alexpott, dawehner, quietone: Remove try...catch from SessionHandler::write

merge-requests/4516/head
catch 2023-07-31 08:54:01 +01:00
parent 2231e59295
commit ba5d33817a
4 changed files with 75 additions and 27 deletions

View File

@ -5,7 +5,6 @@ namespace Drupal\Core\Session;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Database\Connection;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Utility\Error;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
@ -71,32 +70,18 @@ class SessionHandler extends AbstractProxy implements \SessionHandlerInterface {
*/
#[\ReturnTypeWillChange]
public function write(#[\SensitiveParameter] $sid, $value) {
// The exception handler is not active at this point, so we need to do it
// manually.
try {
$request = $this->requestStack->getCurrentRequest();
$fields = [
'uid' => $request->getSession()->get('uid', 0),
'hostname' => $request->getClientIP(),
'session' => $value,
'timestamp' => REQUEST_TIME,
];
$this->connection->merge('sessions')
->keys(['sid' => Crypt::hashBase64($sid)])
->fields($fields)
->execute();
return TRUE;
}
catch (\Exception $exception) {
require_once DRUPAL_ROOT . '/core/includes/errors.inc';
// If we are displaying errors, then do so with no possibility of a
// further uncaught exception being thrown.
if (error_displayable()) {
print '<h1>Uncaught exception thrown in session handler.</h1>';
print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />';
}
return FALSE;
}
$request = $this->requestStack->getCurrentRequest();
$fields = [
'uid' => $request->getSession()->get('uid', 0),
'hostname' => $request->getClientIP(),
'session' => $value,
'timestamp' => REQUEST_TIME,
];
$this->connection->merge('sessions')
->keys(['sid' => Crypt::hashBase64($sid)])
->fields($fields)
->execute();
return TRUE;
}
/**

View File

@ -161,3 +161,13 @@ session_test.has_bag_flag:
no_cache: TRUE
requirements:
_access: 'TRUE'
session_test.trigger_write_exception:
path: '/session-test/trigger-write-exception'
defaults:
_title: 'Trigger an exception when the session is written'
_controller: '\Drupal\session_test\Controller\SessionTestController::triggerWriteException'
options:
no_cache: TRUE
requirements:
_access: 'TRUE'

View File

@ -245,4 +245,43 @@ class SessionTestController extends ControllerBase {
);
}
/**
* Trigger an exception when the session is written.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*/
public function triggerWriteException(Request $request) {
$session = $request->getSession();
$session->set('test_value', 'Ensure session contains some data');
// Move sessions table out of the way.
$schema = \Drupal::database()->schema();
$schema->renameTable('sessions', 'sessions_tmp');
// There needs to be a session table, otherwise
// InstallerRedirectTrait::shouldRedirectToInstaller() will instruct the
// handleException::handleException to redirect to the installer.
$schema->createTable('sessions', [
'description' => "Fake sessions table missing some columns.",
'fields' => [
'sid' => [
'description' => "A fake session ID column.",
'type' => 'varchar_ascii',
'length' => 128,
'not null' => TRUE,
],
],
'primary key' => ['sid'],
]);
drupal_register_shutdown_function(function () {
$schema = \Drupal::database()->schema();
$schema->dropTable('sessions');
$schema->renameTable('sessions_tmp', 'sessions');
});
return new Response();
}
}

View File

@ -358,6 +358,20 @@ class SessionTest extends BrowserTestBase {
$this->assertSession()->statusCodeEquals(200);
}
/**
* Test exception thrown during session write close.
*/
public function testSessionWriteError() {
// Login to ensure a session exists.
$user = $this->drupalCreateUser([]);
$this->drupalLogin($user);
// Trigger an exception in SessionHandler::write().
$this->expectExceptionMessageMatches("/^Drupal\\\\Core\\\\Database\\\\DatabaseExceptionWrapper:/");
$this->drupalGet('/session-test/trigger-write-exception');
$this->assertSession()->statusCodeEquals(500);
}
/**
* Reset the cookie file so that it refers to the specified user.
*/