From 02c5933af8d185cbef4eacc7f732566767fb9b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 21 Oct 2014 14:53:10 +0200 Subject: [PATCH] introduce SessionMiddleWare to control session handling via an annotation --- .../dependencyinjection/dicontainer.php | 13 ++- .../middleware/sessionmiddleware.php | 70 +++++++++++++++ .../middleware/sessionmiddlewaretest.php | 89 +++++++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 lib/private/appframework/middleware/sessionmiddleware.php create mode 100644 tests/lib/appframework/middleware/sessionmiddlewaretest.php diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php index e7efa3fa21..f7fee34721 100644 --- a/lib/private/appframework/dependencyinjection/dicontainer.php +++ b/lib/private/appframework/dependencyinjection/dicontainer.php @@ -31,6 +31,7 @@ use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; use OC\AppFramework\Middleware\Security\SecurityMiddleware; use OC\AppFramework\Middleware\Security\CORSMiddleware; +use OC\AppFramework\Middleware\SessionMiddleware; use OC\AppFramework\Utility\SimpleContainer; use OC\AppFramework\Utility\TimeFactory; use OC\AppFramework\Utility\ControllerMethodReflector; @@ -67,9 +68,10 @@ class DIContainer extends SimpleContainer implements IAppContainer{ */ $this['Request'] = $this->share(function($c) { /** @var $c SimpleContainer */ - /** @var $server IServerContainer */ + /** @var $server SimpleContainer */ $server = $c->query('ServerContainer'); $server->registerParameter('urlParams', $c['urlParams']); + /** @var $server IServerContainer */ return $server->getRequest(); }); @@ -115,6 +117,14 @@ class DIContainer extends SimpleContainer implements IAppContainer{ ); }); + $this['SessionMiddleware'] = $this->share(function($c) use ($app) { + return new SessionMiddleware( + $c['Request'], + $c['ControllerMethodReflector'], + $app->getServer()->getSession() + ); + }); + $middleWares = &$this->middleWares; $this['MiddlewareDispatcher'] = $this->share(function($c) use (&$middleWares) { $dispatcher = new MiddlewareDispatcher(); @@ -125,6 +135,7 @@ class DIContainer extends SimpleContainer implements IAppContainer{ $dispatcher->registerMiddleware($c[$middleWare]); } + $dispatcher->registerMiddleware($c['SessionMiddleware']); return $dispatcher; }); diff --git a/lib/private/appframework/middleware/sessionmiddleware.php b/lib/private/appframework/middleware/sessionmiddleware.php new file mode 100644 index 0000000000..d50880f373 --- /dev/null +++ b/lib/private/appframework/middleware/sessionmiddleware.php @@ -0,0 +1,70 @@ + + * @copyright Thomas Müller 2014 + */ + +namespace OC\AppFramework\Middleware; + +use OC\AppFramework\Utility\ControllerMethodReflector; +use OCP\IRequest; +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Middleware; +use OCP\ISession; + +class SessionMiddleware extends Middleware { + + /** + * @var IRequest + */ + private $request; + + /** + * @var ControllerMethodReflector + */ + private $reflector; + + /** + * @param IRequest $request + * @param ControllerMethodReflector $reflector + */ + public function __construct(IRequest $request, + ControllerMethodReflector $reflector, + ISession $session +) { + $this->request = $request; + $this->reflector = $reflector; + $this->session = $session; + } + + /** + * @param \OCP\AppFramework\Controller $controller + * @param string $methodName + */ + public function beforeController($controller, $methodName) { + $useSession = $this->reflector->hasAnnotation('UseSession'); + if (!$useSession) { + $this->session->close(); + } + } + + /** + * @param \OCP\AppFramework\Controller $controller + * @param string $methodName + * @param Response $response + * @return Response + */ + public function afterController($controller, $methodName, Response $response){ + $useSession = $this->reflector->hasAnnotation('UseSession'); + if ($useSession) { + $this->session->close(); + } + return $response; + } + +} diff --git a/tests/lib/appframework/middleware/sessionmiddlewaretest.php b/tests/lib/appframework/middleware/sessionmiddlewaretest.php new file mode 100644 index 0000000000..13e558bf21 --- /dev/null +++ b/tests/lib/appframework/middleware/sessionmiddlewaretest.php @@ -0,0 +1,89 @@ + + * @copyright Thomas Müller 2014 + */ + + +namespace OC\AppFramework\Middleware\Security; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Middleware\SessionMiddleware; +use OC\AppFramework\Utility\ControllerMethodReflector; +use OCP\AppFramework\Http\Response; + + +class SessionMiddlewareTest extends \PHPUnit_Framework_TestCase { + + /** + * @var ControllerMethodReflector + */ + private $reflector; + + /** + * @var Request + */ + private $request; + + protected function setUp() { + $this->request = new Request(); + $this->reflector = new ControllerMethodReflector(); + } + + /** + * @UseSession + */ + public function testSessionNotClosedOnBeforeController() { + $session = $this->getSessionMock(0); + + $this->reflector->reflect($this, __FUNCTION__); + $middleware = new SessionMiddleware($this->request, $this->reflector, $session); + $middleware->beforeController($this, __FUNCTION__); + } + + /** + * @UseSession + */ + public function testSessionClosedOnAfterController() { + $session = $this->getSessionMock(1); + + $this->reflector->reflect($this, __FUNCTION__); + $middleware = new SessionMiddleware($this->request, $this->reflector, $session); + $middleware->afterController($this, __FUNCTION__, new Response()); + } + + public function testSessionClosedOnBeforeController() { + $session = $this->getSessionMock(1); + + $this->reflector->reflect($this, __FUNCTION__); + $middleware = new SessionMiddleware($this->request, $this->reflector, $session); + $middleware->beforeController($this, __FUNCTION__); + } + + public function testSessionNotClosedOnAfterController() { + $session = $this->getSessionMock(0); + + $this->reflector->reflect($this, __FUNCTION__); + $middleware = new SessionMiddleware($this->request, $this->reflector, $session); + $middleware->afterController($this, __FUNCTION__, new Response()); + } + + /** + * @return mixed + */ + private function getSessionMock($expectedCloseCount) { + $session = $this->getMockBuilder('\OC\Session\Memory') + ->disableOriginalConstructor() + ->getMock(); + + $session->expects($this->exactly($expectedCloseCount)) + ->method('close'); + return $session; + } + +}