diff options
author | Bart Visscher <bartv@thisnet.nl> | 2013-10-04 09:05:20 -0700 |
---|---|---|
committer | Bart Visscher <bartv@thisnet.nl> | 2013-10-04 09:05:20 -0700 |
commit | bae121b16dbabed3ec307ea58e3b8a73ab27161c (patch) | |
tree | cda1d903087731cec2f2eab69f1225b51db6b272 /lib | |
parent | fd34c969d233724399651f6481f32d5c7c1ee18b (diff) | |
parent | aedc427ffd73f9ab249f1722c197205bc366ed8d (diff) | |
download | nextcloud-server-bae121b16dbabed3ec307ea58e3b8a73ab27161c.tar.gz nextcloud-server-bae121b16dbabed3ec307ea58e3b8a73ab27161c.zip |
Merge pull request #5068 from owncloud/improved_request
Improved request
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/appframework/http/request.php | 110 | ||||
-rw-r--r-- | lib/private/route.php | 8 | ||||
-rw-r--r-- | lib/private/server.php | 9 | ||||
-rw-r--r-- | lib/public/irequest.php | 30 |
4 files changed, 110 insertions, 47 deletions
diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php index 34605acdfea..f152956c8cf 100644 --- a/lib/private/appframework/http/request.php +++ b/lib/private/appframework/http/request.php @@ -31,6 +31,8 @@ use OCP\IRequest; class Request implements \ArrayAccess, \Countable, IRequest { + protected $inputStream; + protected $content; protected $items = array(); protected $allowedKeys = array( 'get', @@ -40,17 +42,15 @@ class Request implements \ArrayAccess, \Countable, IRequest { 'env', 'cookies', 'urlParams', - 'params', 'parameters', 'method' ); /** * @param array $vars An associative array with the following optional values: - * @param array 'params' the parsed json array * @param array 'urlParams' the parameters which were matched from the URL * @param array 'get' the $_GET array - * @param array 'post' the $_POST array + * @param array|string 'post' the $_POST array or JSON string * @param array 'files' the $_FILES array * @param array 'server' the $_SERVER array * @param array 'env' the $_ENV array @@ -62,13 +62,27 @@ class Request implements \ArrayAccess, \Countable, IRequest { public function __construct(array $vars=array()) { foreach($this->allowedKeys as $name) { - $this->items[$name] = isset($vars[$name]) + $this->items[$name] = isset($vars[$name]) ? $vars[$name] : array(); } + if (defined('PHPUNIT_RUN') && PHPUNIT_RUN + && in_array('fakeinput', stream_get_wrappers())) { + $this->inputStream = 'fakeinput://data'; + } else { + $this->inputStream = 'php://input'; + } + + // Only 'application/x-www-form-urlencoded' requests are automatically + // transformed by PHP, 'application/json' must be decoded manually. + if ($this->method === 'POST' + && strpos($this->getHeader('Content-Type'), 'application/json') !== false + ) { + $this->items['params'] = $this->items['post'] = json_decode(file_get_contents($this->inputStream), true); + } + $this->items['parameters'] = array_merge( - $this->items['params'], $this->items['get'], $this->items['post'], $this->items['urlParams'] @@ -141,17 +155,22 @@ class Request implements \ArrayAccess, \Countable, IRequest { * $request->myvar; or $request->{'myvar'}; or $request->{$myvar} * Looks in the combined GET, POST and urlParams array. * - * if($request->method !== 'POST') { - * throw new Exception('This function can only be invoked using POST'); - * } + * If you access e.g. ->post but the current HTTP request method + * is GET a \LogicException will be thrown. * * @param string $name The key to look for. + * @throws \LogicException * @return mixed|null */ public function __get($name) { switch($name) { + case 'put': + case 'patch': case 'get': case 'post': + if($this->method !== strtoupper($name)) { + throw new \LogicException(sprintf('%s cannot be accessed in a %s request.', $name, $this->method)); + } case 'files': case 'server': case 'env': @@ -159,9 +178,13 @@ class Request implements \ArrayAccess, \Countable, IRequest { case 'parameters': case 'params': case 'urlParams': - return isset($this->items[$name]) - ? $this->items[$name] - : null; + if(in_array($name, array('put', 'patch'))) { + return $this->getContent($name); + } else { + return isset($this->items[$name]) + ? $this->items[$name] + : null; + } break; case 'method': return $this->items['method']; @@ -280,28 +303,55 @@ class Request implements \ArrayAccess, \Countable, IRequest { /** * Returns the request body content. * - * @param Boolean $asResource If true, a resource will be returned + * If the HTTP request method is PUT and the body + * not application/x-www-form-urlencoded or application/json a stream + * resource is returned, otherwise an array. * - * @return string|resource The request body content or a resource to read the body stream. + * @return array|string|resource The request body content or a resource to read the body stream. * * @throws \LogicException */ - function getContent($asResource = false) { - return null; -// if (false === $this->content || (true === $asResource && null !== $this->content)) { -// throw new \LogicException('getContent() can only be called once when using the resource return type.'); -// } -// -// if (true === $asResource) { -// $this->content = false; -// -// return fopen('php://input', 'rb'); -// } -// -// if (null === $this->content) { -// $this->content = file_get_contents('php://input'); -// } -// -// return $this->content; + protected function getContent() { + if ($this->content === false && $this->method === 'PUT') { + throw new \LogicException( + '"put" can only be accessed once if not ' + . 'application/x-www-form-urlencoded or application/json.' + ); + } + + // If the content can't be parsed into an array then return a stream resource. + if ($this->method === 'PUT' + && strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') === false + && strpos($this->getHeader('Content-Type'), 'application/json') === false + ) { + $this->content = false; + return fopen($this->inputStream, 'rb'); + } + + if (is_null($this->content)) { + $this->content = file_get_contents($this->inputStream); + + /* + * Normal jquery ajax requests are sent as application/x-www-form-urlencoded + * and in $_GET and $_POST PHP transformes the data into an array. + * The first condition mimics this. + * The second condition allows for sending raw application/json data while + * still getting the result as an array. + * + */ + if (strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') !== false) { + parse_str($this->content, $content); + if(is_array($content)) { + $this->content = $content; + } + } elseif (strpos($this->getHeader('Content-Type'), 'application/json') !== false) { + $content = json_decode($this->content, true); + if(is_array($content)) { + $this->content = $content; + } + } + } + + return $this->content; } } diff --git a/lib/private/route.php b/lib/private/route.php index 5901717c094..fb7da456b62 100644 --- a/lib/private/route.php +++ b/lib/private/route.php @@ -52,6 +52,14 @@ class OC_Route extends Route { } /** + * Specify PATCH as the method to use with this route + */ + public function patch() { + $this->method('PATCH'); + return $this; + } + + /** * Defaults to use for this route * * @param array $defaults The defaults diff --git a/lib/private/server.php b/lib/private/server.php index cabb15324ec..ef2007663c6 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -22,14 +22,6 @@ class Server extends SimpleContainer implements IServerContainer { return new ContactsManager(); }); $this->registerService('Request', function($c) { - $params = array(); - - // we json decode the body only in case of content type json - if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') !== false ) { - $params = json_decode(file_get_contents('php://input'), true); - $params = is_array($params) ? $params: array(); - } - return new Request( array( 'get' => $_GET, @@ -41,7 +33,6 @@ class Server extends SimpleContainer implements IServerContainer { 'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD'])) ? $_SERVER['REQUEST_METHOD'] : null, - 'params' => $params, 'urlParams' => $c['urlParams'] ) ); diff --git a/lib/public/irequest.php b/lib/public/irequest.php index 9f335b06f2a..054f15d9eb2 100644 --- a/lib/public/irequest.php +++ b/lib/public/irequest.php @@ -22,6 +22,28 @@ namespace OCP; +/** + * This interface provides an immutable object with with accessors to + * request variables and headers. + * + * Access request variables by method and name. + * + * Examples: + * + * $request->post['myvar']; // Only look for POST variables + * $request->myvar; or $request->{'myvar'}; or $request->{$myvar} + * Looks in the combined GET, POST and urlParams array. + * + * If you access e.g. ->post but the current HTTP request method + * is GET a \LogicException will be thrown. + * + * NOTE: + * - When accessing ->put a stream resource is returned and the accessor + * will return false on subsequent access to ->put or ->patch. + * - When accessing ->patch and the Content-Type is either application/json + * or application/x-www-form-urlencoded (most cases) it will act like ->get + * and ->post and return an array. Otherwise the raw data will be returned. + */ interface IRequest { @@ -85,12 +107,4 @@ interface IRequest { function getCookie($key); - /** - * Returns the request body content. - * - * @param Boolean $asResource If true, a resource will be returned - * @return string|resource The request body content or a resource to read the body stream. - * @throws \LogicException - */ - function getContent($asResource = false); } |