diff options
Diffstat (limited to 'lib/private/AppFramework/OCS/BaseResponse.php')
-rw-r--r-- | lib/private/AppFramework/OCS/BaseResponse.php | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/lib/private/AppFramework/OCS/BaseResponse.php b/lib/private/AppFramework/OCS/BaseResponse.php new file mode 100644 index 00000000000..05ce133db24 --- /dev/null +++ b/lib/private/AppFramework/OCS/BaseResponse.php @@ -0,0 +1,166 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\AppFramework\OCS; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\Response; + +/** + * @psalm-import-type DataResponseType from DataResponse + * @template S of Http::STATUS_* + * @template-covariant T of DataResponseType + * @template H of array<string, mixed> + * @template-extends Response<Http::STATUS_*, array<string, mixed>> + */ +abstract class BaseResponse extends Response { + /** @var array */ + protected $data; + + /** @var string */ + protected $format; + + /** @var ?string */ + protected $statusMessage; + + /** @var ?int */ + protected $itemsCount; + + /** @var ?int */ + protected $itemsPerPage; + + /** + * BaseResponse constructor. + * + * @param DataResponse<S, T, H> $dataResponse + * @param string $format + * @param string|null $statusMessage + * @param int|null $itemsCount + * @param int|null $itemsPerPage + */ + public function __construct(DataResponse $dataResponse, + $format = 'xml', + $statusMessage = null, + $itemsCount = null, + $itemsPerPage = null) { + parent::__construct(); + + $this->format = $format; + $this->statusMessage = $statusMessage; + $this->itemsCount = $itemsCount; + $this->itemsPerPage = $itemsPerPage; + + $this->data = $dataResponse->getData(); + + $this->setHeaders($dataResponse->getHeaders()); + $this->setStatus($dataResponse->getStatus()); + $this->setETag($dataResponse->getETag()); + $this->setLastModified($dataResponse->getLastModified()); + $this->setCookies($dataResponse->getCookies()); + + if ($dataResponse->isThrottled()) { + $throttleMetadata = $dataResponse->getThrottleMetadata(); + $this->throttle($throttleMetadata); + } + + if ($format === 'json') { + $this->addHeader( + 'Content-Type', 'application/json; charset=utf-8' + ); + } else { + $this->addHeader( + 'Content-Type', 'application/xml; charset=utf-8' + ); + } + } + + /** + * @param array<string,string|int> $meta + * @return string + */ + protected function renderResult(array $meta): string { + $status = $this->getStatus(); + if ($status === Http::STATUS_NO_CONTENT + || $status === Http::STATUS_NOT_MODIFIED + || ($status >= 100 && $status <= 199)) { + // Those status codes are not supposed to have a body: + // https://stackoverflow.com/q/8628725 + return ''; + } + + $response = [ + 'ocs' => [ + 'meta' => $meta, + 'data' => $this->data, + ], + ]; + + if ($this->format === 'json') { + return $this->toJson($response); + } + + $writer = new \XMLWriter(); + $writer->openMemory(); + $writer->setIndent(true); + $writer->startDocument(); + $this->toXML($response, $writer); + $writer->endDocument(); + return $writer->outputMemory(true); + } + + /** + * @psalm-taint-escape has_quotes + * @psalm-taint-escape html + */ + protected function toJson(array $array): string { + return \json_encode($array, \JSON_HEX_TAG); + } + + protected function toXML(array $array, \XMLWriter $writer): void { + foreach ($array as $k => $v) { + if ($k === '@attributes' && is_array($v)) { + foreach ($v as $k2 => $v2) { + $writer->writeAttribute($k2, $v2); + } + continue; + } + + if (\is_string($k) && str_starts_with($k, '@')) { + $writer->writeAttribute(substr($k, 1), $v); + continue; + } + + if (\is_numeric($k)) { + $k = 'element'; + } + + if ($v instanceof \stdClass) { + $v = []; + } + + if ($k === '$comment') { + $writer->writeComment($v); + } elseif (\is_array($v)) { + $writer->startElement($k); + $this->toXML($v, $writer); + $writer->endElement(); + } elseif ($v instanceof \JsonSerializable) { + $writer->startElement($k); + $this->toXML($v->jsonSerialize(), $writer); + $writer->endElement(); + } elseif ($v === null) { + $writer->writeElement($k); + } else { + $writer->writeElement($k, (string)$v); + } + } + } + + public function getOCSStatus() { + return parent::getStatus(); + } +} |