Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernhard Posselt <dev@bernhard-posselt.com>2014-05-06 18:29:19 +0400
committerBernhard Posselt <dev@bernhard-posselt.com>2014-05-11 19:54:08 +0400
commit80648da43197c91ed52f36cee8bc818038b88eb6 (patch)
treeea604192691d7b74857ed639311185de0d93504c /lib/private/appframework
parenta252f59cd436d2c005755955bc93ab44544df766 (diff)
implement most of the basic stuff that was suggested in #8290
Diffstat (limited to 'lib/private/appframework')
-rw-r--r--lib/private/appframework/dependencyinjection/dicontainer.php16
-rw-r--r--lib/private/appframework/http/dispatcher.php88
-rw-r--r--lib/private/appframework/middleware/security/securitymiddleware.php16
-rw-r--r--lib/private/appframework/utility/controllermethodreflector.php (renamed from lib/private/appframework/utility/methodannotationreader.php)46
4 files changed, 148 insertions, 18 deletions
diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php
index becd755bda7..c6139df2382 100644
--- a/lib/private/appframework/dependencyinjection/dicontainer.php
+++ b/lib/private/appframework/dependencyinjection/dicontainer.php
@@ -33,6 +33,7 @@ use OC\AppFramework\Middleware\Security\SecurityMiddleware;
use OC\AppFramework\Middleware\Security\CORSMiddleware;
use OC\AppFramework\Utility\SimpleContainer;
use OC\AppFramework\Utility\TimeFactory;
+use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\IApi;
use OCP\AppFramework\IAppContainer;
use OCP\AppFramework\Middleware;
@@ -81,7 +82,11 @@ class DIContainer extends SimpleContainer implements IAppContainer{
});
$this['Dispatcher'] = $this->share(function($c) {
- return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']);
+ return new Dispatcher(
+ $c['Protocol'],
+ $c['MiddlewareDispatcher'],
+ $c['ControllerMethodReflector']
+ );
});
@@ -90,7 +95,11 @@ class DIContainer extends SimpleContainer implements IAppContainer{
*/
$app = $this;
$this['SecurityMiddleware'] = $this->share(function($c) use ($app){
- return new SecurityMiddleware($app, $c['Request']);
+ return new SecurityMiddleware(
+ $app,
+ $c['Request'],
+ $c['ControllerMethodReflector']
+ );
});
$this['CORSMiddleware'] = $this->share(function($c) {
@@ -118,6 +127,9 @@ class DIContainer extends SimpleContainer implements IAppContainer{
return new TimeFactory();
});
+ $this['ControllerMethodReflector'] = $this->share(function($c) {
+ return new ControllerMethodReflector();
+ });
}
diff --git a/lib/private/appframework/http/dispatcher.php b/lib/private/appframework/http/dispatcher.php
index a2afb53f0fa..532e49540b1 100644
--- a/lib/private/appframework/http/dispatcher.php
+++ b/lib/private/appframework/http/dispatcher.php
@@ -26,7 +26,11 @@ namespace OC\AppFramework\Http;
use \OC\AppFramework\Middleware\MiddlewareDispatcher;
use \OC\AppFramework\Http;
+use \OC\AppFramework\Utility\ControllerMethodReflector;
+
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Response;
+use OCP\IRequest;
/**
@@ -36,17 +40,25 @@ class Dispatcher {
private $middlewareDispatcher;
private $protocol;
-
+ private $reflector;
+ private $request;
/**
* @param Http $protocol the http protocol with contains all status headers
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
* runs the middleware
+ * @param ControllerMethodReflector the reflector that is used to inject
+ * the arguments for the controller
+ * @param IRequest $request the incoming request
*/
public function __construct(Http $protocol,
- MiddlewareDispatcher $middlewareDispatcher) {
+ MiddlewareDispatcher $middlewareDispatcher,
+ ControllerMethodReflector $reflector,
+ IRequest $request) {
$this->protocol = $protocol;
$this->middlewareDispatcher = $middlewareDispatcher;
+ $this->reflector = $reflector;
+ $this->request = $request;
}
@@ -63,10 +75,13 @@ class Dispatcher {
$out = array(null, array(), null);
try {
+ // prefill reflector with everything thats needed for the
+ // middlewares
+ $this->reflector->reflect($controller, $methodName);
$this->middlewareDispatcher->beforeController($controller,
$methodName);
- $response = $controller->$methodName();
+ $response = $this->executeController($controller, $methodName);
// if an exception appears, the middleware checks if it can handle the
// exception and creates a response. If no response is created, it is
@@ -98,4 +113,71 @@ class Dispatcher {
}
+ /**
+ * Uses the reflected parameters, types and request parameters to execute
+ * the controller
+ * @return Response
+ */
+ private function executeController($controller, $methodName) {
+ $arguments = array();
+
+ // valid types that will be casted
+ $types = array('int', 'integer', 'bool', 'boolean', 'float');
+
+ foreach($this->reflector->getParameters() as $param) {
+
+ // try to get the parameter from the request object and cast
+ // it to the type annotated in the @param annotation
+ $value = $this->request->getParam($param);
+ $type = $this->reflector->getType($param);
+
+ // if this is submitted using GET or a POST form, 'false' should be
+ // converted to false
+ if(($type === 'bool' || $type === 'boolean') &&
+ $value === 'false' &&
+ (
+ $this->request->method === 'GET' ||
+ (
+ $this->request->method === 'POST' &&
+ strpos($this->request->getHeader('Content-Type'),
+ 'application/x-www-form-urlencoded') !== false
+ )
+ )
+ ) {
+ $value = false;
+
+ } elseif(in_array($type, $types)) {
+ settype($value, $type);
+ }
+
+ $arguments[] = $value;
+ }
+
+ $response = call_user_func_array(array($controller, $methodName), $arguments);
+
+ // format response if not of type response
+ if(!($response instanceof Response)) {
+
+ // get format from the url format or request format parameter
+ $format = $this->request->getParam('format');
+
+ // if none is given try the first Accept header
+ if($format === null) {
+ $header = $this->request->getHeader('Accept');
+ $formats = explode(',', $header);
+
+ if($header !== null && count($formats) > 0) {
+ $accept = strtolower(trim($formats[0]));
+ $format = str_replace('application/', '', $accept);
+ } else {
+ $format = 'json';
+ }
+ }
+
+ $response = $controller->formatResponse($response, $format);
+ }
+
+ return $response;
+ }
+
}
diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php
index 0f160d224ad..b4ace5d0e90 100644
--- a/lib/private/appframework/middleware/security/securitymiddleware.php
+++ b/lib/private/appframework/middleware/security/securitymiddleware.php
@@ -25,7 +25,7 @@
namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Http;
-use OC\AppFramework\Utility\MethodAnnotationReader;
+use OC\AppFramework\Utility\ControllerMethodReflector;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\Http\Response;
@@ -55,10 +55,13 @@ class SecurityMiddleware extends Middleware {
/**
* @param IAppContainer $app
* @param IRequest $request
+ * @param ControllerMethodReflector $reflector
*/
- public function __construct(IAppContainer $app, IRequest $request){
+ public function __construct(IAppContainer $app, IRequest $request,
+ ControllerMethodReflector $reflector){
$this->app = $app;
$this->request = $request;
+ $this->reflector = $reflector;
}
@@ -72,28 +75,25 @@ class SecurityMiddleware extends Middleware {
*/
public function beforeController($controller, $methodName){
- // get annotations from comments
- $annotationReader = new MethodAnnotationReader($controller, $methodName);
-
// this will set the current navigation entry of the app, use this only
// for normal HTML requests and not for AJAX requests
$this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName());
// security checks
- $isPublicPage = $annotationReader->hasAnnotation('PublicPage');
+ $isPublicPage = $this->reflector->hasAnnotation('PublicPage');
if(!$isPublicPage) {
if(!$this->app->isLoggedIn()) {
throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED);
}
- if(!$annotationReader->hasAnnotation('NoAdminRequired')) {
+ if(!$this->reflector->hasAnnotation('NoAdminRequired')) {
if(!$this->app->isAdminUser()) {
throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN);
}
}
}
- if(!$annotationReader->hasAnnotation('NoCSRFRequired')) {
+ if(!$this->reflector->hasAnnotation('NoCSRFRequired')) {
if(!$this->request->passesCSRFCheck()) {
throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED);
}
diff --git a/lib/private/appframework/utility/methodannotationreader.php b/lib/private/appframework/utility/controllermethodreflector.php
index 42060a08529..d6209cae2f2 100644
--- a/lib/private/appframework/utility/methodannotationreader.php
+++ b/lib/private/appframework/utility/controllermethodreflector.php
@@ -28,23 +28,59 @@ namespace OC\AppFramework\Utility;
/**
* Reads and parses annotations from doc comments
*/
-class MethodAnnotationReader {
+class ControllerMethodReflector {
private $annotations;
+ private $types;
+ private $parameters;
+
+ public function __construct() {
+ $this->types = array();
+ $this->parameters = array();
+ $this->annotations = array();
+ }
+
/**
* @param object $object an object or classname
- * @param string $method the method which we want to inspect for annotations
+ * @param string $method the method which we want to inspect
*/
- public function __construct($object, $method){
- $this->annotations = array();
-
+ public function reflect($object, $method){
$reflection = new \ReflectionMethod($object, $method);
$docs = $reflection->getDocComment();
// extract everything prefixed by @ and first letter uppercase
preg_match_all('/@([A-Z]\w+)/', $docs, $matches);
$this->annotations = $matches[1];
+
+ // extract type parameter information
+ preg_match_all('/@param (?<type>\w+) \$(?<var>\w+)/', $docs, $matches);
+ $this->types = array_combine($matches['var'], $matches['type']);
+
+ // get method parameters
+ foreach ($reflection->getParameters() as $param) {
+ $this->parameters[] = $param->name;
+ }
+ }
+
+
+ /**
+ * Inspects the PHPDoc parameters for types
+ * @param strint $parameter the parameter whose type comments should be
+ * parsed
+ * @return string type in the type parameters (@param int $something) would
+ * return int
+ */
+ public function getType($parameter) {
+ return $this->types[$parameter];
+ }
+
+
+ /**
+ * @return array the arguments of the method
+ */
+ public function getParameters() {
+ return $this->parameters;
}