Completed
Push — master ( 3cae27...57eaa4 )
by Morris
23:14 queued 07:02
created

OC_API   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 0
Metric Value
wmc 31
lcom 2
cbo 8
dl 0
loc 185
rs 9.8
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 19 2
B respond() 0 32 6
B toXML() 0 17 5
A requestedFormat() 0 6 3
A setContentType() 0 14 4
A isV2() 0 5 1
B mapStatusCodes() 0 21 8
A renderResult() 0 19 2
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Bernhard Posselt <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Joas Schilling <[email protected]>
10
 * @author Jörn Friedrich Dreyer <[email protected]>
11
 * @author Lukas Reschke <[email protected]>
12
 * @author Michael Gapczynski <[email protected]>
13
 * @author Morris Jobke <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Roeland Jago Douma <[email protected]>
16
 * @author Thomas Müller <[email protected]>
17
 * @author Tom Needham <[email protected]>
18
 * @author Vincent Petry <[email protected]>
19
 *
20
 * @license AGPL-3.0
21
 *
22
 * This code is free software: you can redistribute it and/or modify
23
 * it under the terms of the GNU Affero General Public License, version 3,
24
 * as published by the Free Software Foundation.
25
 *
26
 * This program is distributed in the hope that it will be useful,
27
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29
 * GNU Affero General Public License for more details.
30
 *
31
 * You should have received a copy of the GNU Affero General Public License, version 3,
32
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
33
 *
34
 */
35
use OCP\API;
36
use OCP\AppFramework\Http;
37
38
class OC_API {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
39
40
	/**
41
	 * api actions
42
	 */
43
	protected static $actions = array();
44
45
	/**
46
	 * registers an api call
47
	 * @param string $method the http method
48
	 * @param string $url the url to match
49
	 * @param callable $action the function to run
50
	 * @param string $app the id of the app registering the call
51
	 * @param int $authLevel the level of authentication required for the call
52
	 * @param array $defaults
53
	 * @param array $requirements
54
	 */
55
	public static function register($method, $url, $action, $app,
56
				$authLevel = API::USER_AUTH,
57
				$defaults = array(),
58
				$requirements = array()) {
59
		$name = strtolower($method).$url;
60
		$name = str_replace(array('/', '{', '}'), '_', $name);
61
		if(!isset(self::$actions[$name])) {
62
			$oldCollection = OC::$server->getRouter()->getCurrentCollection();
63
			OC::$server->getRouter()->useCollection('ocs');
64
			OC::$server->getRouter()->create($name, $url)
65
				->method($method)
66
				->defaults($defaults)
67
				->requirements($requirements)
68
				->action('OC_API', 'call');
69
			self::$actions[$name] = array();
70
			OC::$server->getRouter()->useCollection($oldCollection);
71
		}
72
		self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel);
73
	}
74
75
	/**
76
	 * respond to a call
77
	 * @param \OC\OCS\Result $result
78
	 * @param string $format the format xml|json
79
	 */
80
	public static function respond($result, $format='xml') {
81
		$request = \OC::$server->getRequest();
82
83
		// Send 401 headers if unauthorised
84
		if($result->getStatusCode() === API::RESPOND_UNAUTHORISED) {
85
			// If request comes from JS return dummy auth request
86
			if($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
87
				header('WWW-Authenticate: DummyBasic realm="Authorisation Required"');
88
			} else {
89
				header('WWW-Authenticate: Basic realm="Authorisation Required"');
90
			}
91
			header('HTTP/1.0 401 Unauthorized');
92
		}
93
94
		foreach($result->getHeaders() as $name => $value) {
95
			header($name . ': ' . $value);
96
		}
97
98
		$meta = $result->getMeta();
99
		$data = $result->getData();
100
		if (self::isV2($request)) {
101
			$statusCode = self::mapStatusCodes($result->getStatusCode());
102
			if (!is_null($statusCode)) {
103
				$meta['statuscode'] = $statusCode;
104
				OC_Response::setStatus($statusCode);
105
			}
106
		}
107
108
		self::setContentType($format);
109
		$body = self::renderResult($format, $meta, $data);
110
		echo $body;
111
	}
112
113
	/**
114
	 * @param XMLWriter $writer
115
	 */
116
	private static function toXML($array, $writer) {
117
		foreach($array as $k => $v) {
118
			if ($k[0] === '@') {
119
				$writer->writeAttribute(substr($k, 1), $v);
120
				continue;
121
			} else if (is_numeric($k)) {
122
				$k = 'element';
123
			}
124
			if(is_array($v)) {
125
				$writer->startElement($k);
126
				self::toXML($v, $writer);
127
				$writer->endElement();
128
			} else {
129
				$writer->writeElement($k, $v);
130
			}
131
		}
132
	}
133
134
	/**
135
	 * @return string
136
	 */
137
	public static function requestedFormat() {
0 ignored issues
show
Coding Style introduced by
requestedFormat uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
138
		$formats = array('json', 'xml');
139
140
		$format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml';
141
		return $format;
142
	}
143
144
	/**
145
	 * Based on the requested format the response content type is set
146
	 * @param string $format
147
	 */
148
	public static function setContentType($format = null) {
149
		$format = is_null($format) ? self::requestedFormat() : $format;
150
		if ($format === 'xml') {
151
			header('Content-type: text/xml; charset=UTF-8');
152
			return;
153
		}
154
155
		if ($format === 'json') {
156
			header('Content-Type: application/json; charset=utf-8');
157
			return;
158
		}
159
160
		header('Content-Type: application/octet-stream; charset=utf-8');
161
	}
162
163
	/**
164
	 * @param \OCP\IRequest $request
165
	 * @return bool
166
	 */
167
	protected static function isV2(\OCP\IRequest $request) {
168
		$script = $request->getScriptName();
169
170
		return substr($script, -11) === '/ocs/v2.php';
171
	}
172
173
	/**
174
	 * @param integer $sc
175
	 * @return int
176
	 */
177
	public static function mapStatusCodes($sc) {
178
		switch ($sc) {
179
			case API::RESPOND_NOT_FOUND:
180
				return Http::STATUS_NOT_FOUND;
181
			case API::RESPOND_SERVER_ERROR:
182
				return Http::STATUS_INTERNAL_SERVER_ERROR;
183
			case API::RESPOND_UNKNOWN_ERROR:
184
				return Http::STATUS_INTERNAL_SERVER_ERROR;
185
			case API::RESPOND_UNAUTHORISED:
186
				// already handled for v1
187
				return null;
188
			case 100:
189
				return Http::STATUS_OK;
190
		}
191
		// any 2xx, 4xx and 5xx will be used as is
192
		if ($sc >= 200 && $sc < 600) {
193
			return $sc;
194
		}
195
196
		return Http::STATUS_BAD_REQUEST;
197
	}
198
199
	/**
200
	 * @param string $format
201
	 * @return string
202
	 */
203
	public static function renderResult($format, $meta, $data) {
204
		$response = array(
205
			'ocs' => array(
206
				'meta' => $meta,
207
				'data' => $data,
208
			),
209
		);
210
		if ($format == 'json') {
211
			return OC_JSON::encode($response);
212
		}
213
214
		$writer = new XMLWriter();
215
		$writer->openMemory();
216
		$writer->setIndent(true);
217
		$writer->startDocument();
218
		self::toXML($response, $writer);
219
		$writer->endDocument();
220
		return $writer->outputMemory(true);
221
	}
222
}
223