mirror of
https://github.com/nextcloud/server.git
synced 2025-10-26 19:21:34 +00:00
Merge pull request #32162 from nextcloud/enh/session-reopen
Avoid locking the php session
This commit is contained in:
commit
1a2c008011
@ -256,6 +256,17 @@ $CONFIG = [
|
||||
*/
|
||||
'session_lifetime' => 60 * 60 * 24,
|
||||
|
||||
/**
|
||||
* `true` enabled a relaxed session timeout, where the session timeout would no longer be
|
||||
* handled by Nextcloud but by either the PHP garbage collection or the expiration of
|
||||
* potential other session backends like redis.
|
||||
*
|
||||
* This may lead to sessions being available for longer than what session_lifetime uses but
|
||||
* comes with performance benefits as sessions are no longer a locking operation for concurrent
|
||||
* requests.
|
||||
*/
|
||||
'session_relaxed_expiry' => false,
|
||||
|
||||
/**
|
||||
* Enable or disable session keep-alive when a user is logged in to the Web UI.
|
||||
* Enabling this sends a "heartbeat" to the server to keep it from timing out.
|
||||
|
||||
17
lib/base.php
17
lib/base.php
@ -445,7 +445,9 @@ class OC {
|
||||
die();
|
||||
}
|
||||
|
||||
//try to set the session lifetime
|
||||
$sessionLifeTime = self::getSessionLifeTime();
|
||||
@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
|
||||
|
||||
// session timeout
|
||||
if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
|
||||
@ -455,7 +457,10 @@ class OC {
|
||||
\OC::$server->getUserSession()->logout();
|
||||
}
|
||||
|
||||
$session->set('LAST_ACTIVITY', time());
|
||||
if (!self::hasSessionRelaxedExpiry()) {
|
||||
$session->set('LAST_ACTIVITY', time());
|
||||
}
|
||||
$session->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -465,6 +470,13 @@ class OC {
|
||||
return \OC::$server->getConfig()->getSystemValue('session_lifetime', 60 * 60 * 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if the session expiry should only be done by gc instead of an explicit timeout
|
||||
*/
|
||||
public static function hasSessionRelaxedExpiry(): bool {
|
||||
return \OC::$server->getConfig()->getSystemValue('session_relaxed_expiry', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to set some values to the required Nextcloud default
|
||||
*/
|
||||
@ -707,9 +719,6 @@ class OC {
|
||||
$config->deleteAppValue('core', 'cronErrors');
|
||||
}
|
||||
}
|
||||
//try to set the session lifetime
|
||||
$sessionLifeTime = self::getSessionLifeTime();
|
||||
@ini_set('gc_maxlifetime', (string)$sessionLifeTime);
|
||||
|
||||
// User and Groups
|
||||
if (!$systemConfig->getValue("installed", false)) {
|
||||
|
||||
@ -51,8 +51,8 @@ class SessionMiddleware extends Middleware {
|
||||
*/
|
||||
public function beforeController($controller, $methodName) {
|
||||
$useSession = $this->reflector->hasAnnotation('UseSession');
|
||||
if (!$useSession) {
|
||||
$this->session->close();
|
||||
if ($useSession) {
|
||||
$this->session->reopen();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -97,8 +97,17 @@ class CryptoSessionData implements \ArrayAccess, ISession {
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set(string $key, $value) {
|
||||
if ($this->get($key) === $value) {
|
||||
// Do not write the session if the value hasn't changed to avoid reopening
|
||||
return;
|
||||
}
|
||||
|
||||
$reopened = $this->reopen();
|
||||
$this->sessionValues[$key] = $value;
|
||||
$this->isModified = true;
|
||||
if ($reopened) {
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,9 +140,13 @@ class CryptoSessionData implements \ArrayAccess, ISession {
|
||||
* @param string $key
|
||||
*/
|
||||
public function remove(string $key) {
|
||||
$reopened = $this->reopen();
|
||||
$this->isModified = true;
|
||||
unset($this->sessionValues[$key]);
|
||||
$this->session->remove(self::encryptedSessionName);
|
||||
if ($reopened) {
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,6 +162,10 @@ class CryptoSessionData implements \ArrayAccess, ISession {
|
||||
$this->session->clear();
|
||||
}
|
||||
|
||||
public function reopen(): bool {
|
||||
return $this->session->reopen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around session_regenerate_id
|
||||
*
|
||||
|
||||
@ -68,8 +68,11 @@ class Internal extends Session {
|
||||
* @param integer $value
|
||||
*/
|
||||
public function set(string $key, $value) {
|
||||
$this->validateSession();
|
||||
$reopened = $this->reopen();
|
||||
$_SESSION[$key] = $value;
|
||||
if ($reopened) {
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,6 +104,7 @@ class Internal extends Session {
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
$this->reopen();
|
||||
$this->invoke('session_unset');
|
||||
$this->regenerateId();
|
||||
$this->startSession(true);
|
||||
@ -120,6 +124,7 @@ class Internal extends Session {
|
||||
* @return void
|
||||
*/
|
||||
public function regenerateId(bool $deleteOldSession = true, bool $updateToken = false) {
|
||||
$this->reopen();
|
||||
$oldId = null;
|
||||
|
||||
if ($updateToken) {
|
||||
@ -171,8 +176,14 @@ class Internal extends Session {
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function reopen() {
|
||||
throw new \Exception('The session cannot be reopened - reopen() is only to be used in unit testing.');
|
||||
public function reopen(): bool {
|
||||
if ($this->sessionClosed) {
|
||||
$this->startSession(false, false);
|
||||
$this->sessionClosed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,7 +225,11 @@ class Internal extends Session {
|
||||
}
|
||||
}
|
||||
|
||||
private function startSession(bool $silence = false) {
|
||||
$this->invoke('session_start', [['cookie_samesite' => 'Lax']], $silence);
|
||||
private function startSession(bool $silence = false, bool $readAndClose = true) {
|
||||
$sessionParams = ['cookie_samesite' => 'Lax'];
|
||||
if (\OC::hasSessionRelaxedExpiry()) {
|
||||
$sessionParams['read_and_close'] = $readAndClose;
|
||||
}
|
||||
$this->invoke('session_start', [$sessionParams], $silence);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +53,6 @@ class Memory extends Session {
|
||||
* @param integer $value
|
||||
*/
|
||||
public function set(string $key, $value) {
|
||||
$this->validateSession();
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
|
||||
@ -80,7 +79,6 @@ class Memory extends Session {
|
||||
* @param string $key
|
||||
*/
|
||||
public function remove(string $key) {
|
||||
$this->validateSession();
|
||||
unset($this->data[$key]);
|
||||
}
|
||||
|
||||
@ -110,8 +108,10 @@ class Memory extends Session {
|
||||
/**
|
||||
* Helper function for PHPUnit execution - don't use in non-test code
|
||||
*/
|
||||
public function reopen() {
|
||||
public function reopen(): bool {
|
||||
$reopened = $this->sessionClosed;
|
||||
$this->sessionClosed = false;
|
||||
return $reopened;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -83,6 +83,14 @@ interface ISession {
|
||||
*/
|
||||
public function clear();
|
||||
|
||||
/**
|
||||
* Reopen a session for writing again
|
||||
*
|
||||
* @return bool true if the session was actually reopened, otherwise false
|
||||
* @since 25.0.0
|
||||
*/
|
||||
public function reopen(): bool;
|
||||
|
||||
/**
|
||||
* Close the session and release the lock
|
||||
* @since 7.0.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user