summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernhard Posselt <Raydiation@users.noreply.github.com>2015-08-05 17:28:08 +0200
committerBernhard Posselt <Raydiation@users.noreply.github.com>2015-08-05 17:28:08 +0200
commit7cb0934fa27a512b2e409361fe283d9c15560327 (patch)
tree1e2f9fcb7433e53e8c072aab6f3d0c81713c01f7
parent314fc11e1beb37e683cfa874e74ae3103632d803 (diff)
parent6c46430cdb6edf411142d0a73fb888391ea86fd7 (diff)
downloadnextcloud-server-7cb0934fa27a512b2e409361fe283d9c15560327.tar.gz
nextcloud-server-7cb0934fa27a512b2e409361fe283d9c15560327.zip
Merge pull request #18035 from owncloud/ocs-2.0
Adding ocs/v2.php with status code mapper
-rw-r--r--lib/private/api.php113
-rw-r--r--lib/private/ocs.php145
-rw-r--r--lib/private/ocs/exception.php34
-rw-r--r--lib/public/appframework/http/ocsresponse.php28
-rw-r--r--lib/public/appframework/ocscontroller.php11
-rw-r--r--ocs/v1.php2
-rw-r--r--ocs/v2.php22
-rw-r--r--tests/lib/appframework/controller/OCSControllerTest.php12
-rw-r--r--tests/lib/appframework/http/OCSResponseTest.php5
-rw-r--r--tests/ocs/response.php42
10 files changed, 211 insertions, 203 deletions
diff --git a/lib/private/api.php b/lib/private/api.php
index 8e483b7efe9..86d7558526b 100644
--- a/lib/private/api.php
+++ b/lib/private/api.php
@@ -1,4 +1,7 @@
<?php
+use OCP\API;
+use OCP\AppFramework\Http;
+
/**
* @author Bart Visscher <bartv@thisnet.nl>
* @author Bernhard Posselt <dev@bernhard-posselt.com>
@@ -82,7 +85,7 @@ class OC_API {
* @param array $requirements
*/
public static function register($method, $url, $action, $app,
- $authLevel = \OCP\API::USER_AUTH,
+ $authLevel = API::USER_AUTH,
$defaults = array(),
$requirements = array()) {
$name = strtolower($method).$url;
@@ -123,7 +126,7 @@ class OC_API {
if(!self::isAuthorised($action)) {
$responses[] = array(
'app' => $action['app'],
- 'response' => new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED, 'Unauthorised'),
+ 'response' => new OC_OCS_Result(null, API::RESPOND_UNAUTHORISED, 'Unauthorised'),
'shipped' => OC_App::isShipped($action['app']),
);
continue;
@@ -131,7 +134,7 @@ class OC_API {
if(!is_callable($action['action'])) {
$responses[] = array(
'app' => $action['app'],
- 'response' => new OC_OCS_Result(null, \OCP\API::RESPOND_NOT_FOUND, 'Api method not found'),
+ 'response' => new OC_OCS_Result(null, API::RESPOND_NOT_FOUND, 'Api method not found'),
'shipped' => OC_App::isShipped($action['app']),
);
continue;
@@ -252,15 +255,15 @@ class OC_API {
private static function isAuthorised($action) {
$level = $action['authlevel'];
switch($level) {
- case \OCP\API::GUEST_AUTH:
+ case API::GUEST_AUTH:
// Anyone can access
return true;
break;
- case \OCP\API::USER_AUTH:
+ case API::USER_AUTH:
// User required
return self::loginUser();
break;
- case \OCP\API::SUBADMIN_AUTH:
+ case API::SUBADMIN_AUTH:
// Check for subadmin
$user = self::loginUser();
if(!$user) {
@@ -275,7 +278,7 @@ class OC_API {
}
}
break;
- case \OCP\API::ADMIN_AUTH:
+ case API::ADMIN_AUTH:
// Check for admin
$user = self::loginUser();
if(!$user) {
@@ -342,28 +345,21 @@ class OC_API {
*/
public static function respond($result, $format='xml') {
// Send 401 headers if unauthorised
- if($result->getStatusCode() === \OCP\API::RESPOND_UNAUTHORISED) {
+ if($result->getStatusCode() === API::RESPOND_UNAUTHORISED) {
header('WWW-Authenticate: Basic realm="Authorisation Required"');
header('HTTP/1.0 401 Unauthorized');
}
- $response = array(
- 'ocs' => array(
- 'meta' => $result->getMeta(),
- 'data' => $result->getData(),
- ),
- );
- if ($format == 'json') {
- OC_JSON::encodedPrint($response);
- } else if ($format == 'xml') {
- header('Content-type: text/xml; charset=UTF-8');
- $writer = new XMLWriter();
- $writer->openMemory();
- $writer->setIndent( true );
- $writer->startDocument();
- self::toXML($response, $writer);
- $writer->endDocument();
- echo $writer->outputMemory(true);
+
+ if (self::isV2()) {
+ $statusCode = self::mapStatusCodes($result->getStatusCode());
+ if (!is_null($statusCode)) {
+ OC_Response::setStatus($statusCode);
+ }
}
+
+ self::setContentType($format);
+ $body = self::renderResult($result, $format);
+ echo $body;
}
/**
@@ -400,8 +396,8 @@ class OC_API {
/**
* Based on the requested format the response content type is set
*/
- public static function setContentType() {
- $format = self::requestedFormat();
+ public static function setContentType($format = null) {
+ $format = is_null($format) ? self::requestedFormat() : $format;
if ($format === 'xml') {
header('Content-type: text/xml; charset=UTF-8');
return;
@@ -415,5 +411,68 @@ class OC_API {
header('Content-Type: application/octet-stream; charset=utf-8');
}
+ /**
+ * @return boolean
+ */
+ private static function isV2() {
+ $request = \OC::$server->getRequest();
+ $script = $request->getScriptName();
+ return $script === '/ocs/v2.php';
+ }
+
+ /**
+ * @param integer $sc
+ * @return int
+ */
+ public static function mapStatusCodes($sc) {
+ switch ($sc) {
+ case API::RESPOND_NOT_FOUND:
+ return Http::STATUS_NOT_FOUND;
+ case API::RESPOND_SERVER_ERROR:
+ return Http::STATUS_INTERNAL_SERVER_ERROR;
+ case API::RESPOND_UNKNOWN_ERROR:
+ return Http::STATUS_INTERNAL_SERVER_ERROR;
+ case API::RESPOND_UNAUTHORISED:
+ // already handled for v1
+ return null;
+ case 100:
+ return Http::STATUS_OK;
+ }
+ // any 2xx, 4xx and 5xx will be used as is
+ if ($sc >= 200 && $sc < 600) {
+ return $sc;
+ }
+
+ // any error codes > 100 are treated as client errors
+ if ($sc > 100 && $sc < 200) {
+ return Http::STATUS_BAD_REQUEST;
+ }
+ return Http::STATUS_OK;
+ }
+
+ /**
+ * @param OC_OCS_Result $result
+ * @param string $format
+ * @return string
+ */
+ public static function renderResult($result, $format) {
+ $response = array(
+ 'ocs' => array(
+ 'meta' => $result->getMeta(),
+ 'data' => $result->getData(),
+ ),
+ );
+ if ($format == 'json') {
+ return OC_JSON::encode($response);
+ }
+
+ $writer = new XMLWriter();
+ $writer->openMemory();
+ $writer->setIndent(true);
+ $writer->startDocument();
+ self::toXML($response, $writer);
+ $writer->endDocument();
+ return $writer->outputMemory(true);
+ }
}
diff --git a/lib/private/ocs.php b/lib/private/ocs.php
index 6d166f8adb0..bb1aabf8f18 100644
--- a/lib/private/ocs.php
+++ b/lib/private/ocs.php
@@ -28,6 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+use OCP\API;
/**
* Class to handle open collaboration services API requests
@@ -64,8 +65,7 @@ class OC_OCS {
}
}
if ($data === false) {
- echo self::generateXml('', 'fail', 400, 'Bad request. Please provide a valid '.$key);
- exit();
+ throw new \OC\OCS\Exception(new OC_OCS_Result(null, 400, 'Bad request. Please provide a valid '.$key));
} else {
// NOTE: Is the raw type necessary? It might be a little risky without sanitization
if ($type == 'raw') return $data;
@@ -78,23 +78,12 @@ class OC_OCS {
}
public static function notFound() {
- if($_SERVER['REQUEST_METHOD'] == 'GET') {
- $method='get';
- }elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
- $method='put';
- }elseif($_SERVER['REQUEST_METHOD'] == 'POST') {
- $method='post';
- }else{
- echo('internal server error: method not supported');
- exit();
- }
-
- $format = self::readData($method, 'format', 'text', '');
+ $format = OC_API::requestedFormat();
$txt='Invalid query, please check the syntax. API specifications are here:'
.' http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
$txt.=OC_OCS::getDebugOutput();
- echo(OC_OCS::generateXml($format, 'failed', 999, $txt));
+ OC_API::respond(new OC_OCS_Result(null, API::RESPOND_UNKNOWN_ERROR, $txt), $format);
}
/**
@@ -110,130 +99,4 @@ class OC_OCS {
if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n";
return($txt);
}
-
-
- /**
- * generates the xml or json response for the API call from an multidimenional data array.
- * @param string $format
- * @param string $status
- * @param string $statuscode
- * @param string $message
- * @param array $data
- * @param string $tag
- * @param string $tagattribute
- * @param int $dimension
- * @param int|string $itemscount
- * @param int|string $itemsperpage
- * @return string xml/json
- */
- public static function generateXml($format, $status, $statuscode,
- $message, $data=array(), $tag='', $tagattribute='', $dimension=-1, $itemscount='', $itemsperpage='') {
- if($format=='json') {
- $json=array();
- $json['status']=$status;
- $json['statuscode']=$statuscode;
- $json['message']=$message;
- $json['totalitems']=$itemscount;
- $json['itemsperpage']=$itemsperpage;
- $json['data']=$data;
- return(json_encode($json));
- }else{
- $txt='';
- $writer = xmlwriter_open_memory();
- xmlwriter_set_indent( $writer, 2 );
- xmlwriter_start_document($writer );
- xmlwriter_start_element($writer, 'ocs');
- xmlwriter_start_element($writer, 'meta');
- xmlwriter_write_element($writer, 'status', $status);
- xmlwriter_write_element($writer, 'statuscode', $statuscode);
- xmlwriter_write_element($writer, 'message', $message);
- if($itemscount<>'') xmlwriter_write_element($writer, 'totalitems', $itemscount);
- if(!empty($itemsperpage)) xmlwriter_write_element($writer, 'itemsperpage', $itemsperpage);
- xmlwriter_end_element($writer);
- if($dimension=='0') {
- // 0 dimensions
- xmlwriter_write_element($writer, 'data', $data);
-
- }elseif($dimension=='1') {
- xmlwriter_start_element($writer, 'data');
- foreach($data as $key=>$entry) {
- xmlwriter_write_element($writer, $key, $entry);
- }
- xmlwriter_end_element($writer);
-
- }elseif($dimension=='2') {
- xmlwriter_start_element($writer, 'data');
- foreach($data as $entry) {
- xmlwriter_start_element($writer, $tag);
- if(!empty($tagattribute)) {
- xmlwriter_write_attribute($writer, 'details', $tagattribute);
- }
- foreach($entry as $key=>$value) {
- if(is_array($value)) {
- foreach($value as $k=>$v) {
- xmlwriter_write_element($writer, $k, $v);
- }
- } else {
- xmlwriter_write_element($writer, $key, $value);
- }
- }
- xmlwriter_end_element($writer);
- }
- xmlwriter_end_element($writer);
-
- }elseif($dimension=='3') {
- xmlwriter_start_element($writer, 'data');
- foreach($data as $entrykey=>$entry) {
- xmlwriter_start_element($writer, $tag);
- if(!empty($tagattribute)) {
- xmlwriter_write_attribute($writer, 'details', $tagattribute);
- }
- foreach($entry as $key=>$value) {
- if(is_array($value)) {
- xmlwriter_start_element($writer, $entrykey);
- foreach($value as $k=>$v) {
- xmlwriter_write_element($writer, $k, $v);
- }
- xmlwriter_end_element($writer);
- } else {
- xmlwriter_write_element($writer, $key, $value);
- }
- }
- xmlwriter_end_element($writer);
- }
- xmlwriter_end_element($writer);
- }elseif($dimension=='dynamic') {
- xmlwriter_start_element($writer, 'data');
- OC_OCS::toxml($writer, $data, 'comment');
- xmlwriter_end_element($writer);
- }
-
- xmlwriter_end_element($writer);
-
- xmlwriter_end_document( $writer );
- $txt.=xmlwriter_output_memory( $writer );
- unset($writer);
- return($txt);
- }
- }
-
- /**
- * @param resource $writer
- * @param array $data
- * @param string $node
- */
- public static function toXml($writer, $data, $node) {
- foreach($data as $key => $value) {
- if (is_numeric($key)) {
- $key = $node;
- }
- if (is_array($value)) {
- xmlwriter_start_element($writer, $key);
- OC_OCS::toxml($writer, $value, $node);
- xmlwriter_end_element($writer);
- }else{
- xmlwriter_write_element($writer, $key, $value);
- }
- }
- }
}
diff --git a/lib/private/ocs/exception.php b/lib/private/ocs/exception.php
new file mode 100644
index 00000000000..93bee773771
--- /dev/null
+++ b/lib/private/ocs/exception.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\OCS;
+
+class Exception extends \Exception {
+
+ public function __construct(\OC_OCS_Result $result) {
+ $this->result = $result;
+ }
+
+ public function getResult() {
+ return $this->result;
+ }
+
+}
diff --git a/lib/public/appframework/http/ocsresponse.php b/lib/public/appframework/http/ocsresponse.php
index 52d3c2fa665..2e788a52bb9 100644
--- a/lib/public/appframework/http/ocsresponse.php
+++ b/lib/public/appframework/http/ocsresponse.php
@@ -41,38 +41,26 @@ class OCSResponse extends Response {
private $format;
private $statuscode;
private $message;
- private $tag;
- private $tagattribute;
- private $dimension;
private $itemscount;
private $itemsperpage;
/**
* generates the xml or json response for the API call from an multidimenional data array.
* @param string $format
- * @param string $status
- * @param string $statuscode
+ * @param int $statuscode
* @param string $message
* @param array $data
- * @param string $tag
- * @param string $tagattribute
- * @param int $dimension
* @param int|string $itemscount
* @param int|string $itemsperpage
* @since 8.1.0
*/
- public function __construct($format, $status, $statuscode, $message,
- $data=[], $tag='', $tagattribute='',
- $dimension=-1, $itemscount='',
+ public function __construct($format, $statuscode, $message,
+ $data=[], $itemscount='',
$itemsperpage='') {
$this->format = $format;
- $this->setStatus($status);
$this->statuscode = $statuscode;
$this->message = $message;
$this->data = $data;
- $this->tag = $tag;
- $this->tagattribute = $tagattribute;
- $this->dimension = $dimension;
$this->itemscount = $itemscount;
$this->itemsperpage = $itemsperpage;
@@ -93,11 +81,11 @@ class OCSResponse extends Response {
* @since 8.1.0
*/
public function render() {
- return OC_OCS::generateXml(
- $this->format, $this->getStatus(), $this->statuscode, $this->message,
- $this->data, $this->tag, $this->tagattribute, $this->dimension,
- $this->itemscount, $this->itemsperpage
- );
+ $r = new \OC_OCS_Result($this->data, $this->statuscode, $this->message);
+ $r->setTotalItems($this->itemscount);
+ $r->setItemsPerPage($this->itemsperpage);
+
+ return \OC_API::renderResult($r, $this->format);
}
diff --git a/lib/public/appframework/ocscontroller.php b/lib/public/appframework/ocscontroller.php
index 602731fe761..55ba518020a 100644
--- a/lib/public/appframework/ocscontroller.php
+++ b/lib/public/appframework/ocscontroller.php
@@ -42,7 +42,7 @@ abstract class OCSController extends ApiController {
* constructor of the controller
* @param string $appName the name of the app
* @param IRequest $request an instance of the request
- * @param string $corsMethods comma seperated string of HTTP verbs which
+ * @param string $corsMethods comma separated string of HTTP verbs which
* should be allowed for websites or webapps when calling your API, defaults to
* 'PUT, POST, GET, DELETE, PATCH'
* @param string $corsAllowedHeaders comma seperated string of HTTP headers
@@ -80,13 +80,9 @@ abstract class OCSController extends ApiController {
}
$params = [
- 'status' => 'OK',
'statuscode' => 100,
'message' => 'OK',
'data' => [],
- 'tag' => '',
- 'tagattribute' => '',
- 'dimension' => 'dynamic',
'itemscount' => '',
'itemsperpage' => ''
];
@@ -96,9 +92,8 @@ abstract class OCSController extends ApiController {
}
return new OCSResponse(
- $format, $params['status'], $params['statuscode'],
- $params['message'], $params['data'], $params['tag'],
- $params['tagattribute'], $params['dimension'],
+ $format, $params['statuscode'],
+ $params['message'], $params['data'],
$params['itemscount'], $params['itemsperpage']
);
}
diff --git a/ocs/v1.php b/ocs/v1.php
index 2829cf08c57..c5c18d20b8a 100644
--- a/ocs/v1.php
+++ b/ocs/v1.php
@@ -56,5 +56,7 @@ try {
} catch (MethodNotAllowedException $e) {
OC_API::setContentType();
OC_Response::setStatus(405);
+} catch (\OC\OCS\Exception $ex) {
+ OC_API::respond($ex->getResult(), OC_API::requestedFormat());
}
diff --git a/ocs/v2.php b/ocs/v2.php
new file mode 100644
index 00000000000..b2e3b259727
--- /dev/null
+++ b/ocs/v2.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+require_once 'v1.php';
diff --git a/tests/lib/appframework/controller/OCSControllerTest.php b/tests/lib/appframework/controller/OCSControllerTest.php
index 11a9d45eb92..92b092cf0e9 100644
--- a/tests/lib/appframework/controller/OCSControllerTest.php
+++ b/tests/lib/appframework/controller/OCSControllerTest.php
@@ -69,9 +69,11 @@ class OCSControllerTest extends \Test\TestCase {
$expected = "<?xml version=\"1.0\"?>\n" .
"<ocs>\n" .
" <meta>\n" .
- " <status>OK</status>\n" .
+ " <status>failure</status>\n" .
" <statuscode>400</statuscode>\n" .
" <message>OK</message>\n" .
+ " <totalitems></totalitems>\n" .
+ " <itemsperpage></itemsperpage>\n" .
" </meta>\n" .
" <data>\n" .
" <test>hi</test>\n" .
@@ -99,9 +101,11 @@ class OCSControllerTest extends \Test\TestCase {
$expected = "<?xml version=\"1.0\"?>\n" .
"<ocs>\n" .
" <meta>\n" .
- " <status>OK</status>\n" .
+ " <status>failure</status>\n" .
" <statuscode>400</statuscode>\n" .
" <message>OK</message>\n" .
+ " <totalitems></totalitems>\n" .
+ " <itemsperpage></itemsperpage>\n" .
" </meta>\n" .
" <data>\n" .
" <test>hi</test>\n" .
@@ -126,8 +130,8 @@ class OCSControllerTest extends \Test\TestCase {
$this->getMock('\OCP\Security\ISecureRandom'),
$this->getMock('\OCP\IConfig')
));
- $expected = '{"status":"OK","statuscode":400,"message":"OK",' .
- '"totalitems":"","itemsperpage":"","data":{"test":"hi"}}';
+ $expected = '{"ocs":{"meta":{"status":"failure","statuscode":400,"message":"OK",' .
+ '"totalitems":"","itemsperpage":""},"data":{"test":"hi"}}}';
$params = [
'data' => [
'test' => 'hi'
diff --git a/tests/lib/appframework/http/OCSResponseTest.php b/tests/lib/appframework/http/OCSResponseTest.php
index 111dc7ad0a3..1ca3e330bad 100644
--- a/tests/lib/appframework/http/OCSResponseTest.php
+++ b/tests/lib/appframework/http/OCSResponseTest.php
@@ -47,14 +47,13 @@ class OCSResponseTest extends \Test\TestCase {
public function testRender() {
$response = new OCSResponse(
- 'xml', 'status', 2, 'message', ['test' => 'hi'], 'tag', 'abc',
- 'dynamic', 3, 4
+ 'xml', 2, 'message', ['test' => 'hi'], 3, 4
);
$out = $response->render();
$expected = "<?xml version=\"1.0\"?>\n" .
"<ocs>\n" .
" <meta>\n" .
- " <status>status</status>\n" .
+ " <status>failure</status>\n" .
" <statuscode>2</statuscode>\n" .
" <message>message</message>\n" .
" <totalitems>3</totalitems>\n" .
diff --git a/tests/ocs/response.php b/tests/ocs/response.php
new file mode 100644
index 00000000000..0d5883fa4cc
--- /dev/null
+++ b/tests/ocs/response.php
@@ -0,0 +1,42 @@
+<?php
+use OCP\AppFramework\Http;
+
+/**
+ * @author Thomas Müller <thomas.mueller@tmit.eu>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+class OcsResponseTest extends \Test\TestCase {
+
+ /**
+ * @dataProvider providesStatusCodes
+ */
+ public function testStatusCodeMapper($expected, $sc) {
+ $result = OC_API::mapStatusCodes($sc);
+ $this->assertEquals($expected, $result);
+ }
+
+ public function providesStatusCodes() {
+ return [
+ [Http::STATUS_OK, 100],
+ [Http::STATUS_BAD_REQUEST, 104],
+ [Http::STATUS_OK, 1000],
+ [201, 201],
+ ];
+ }
+}