zx/vendor/obs/esdk-obs-php/Obs/Internal/GetResponseTrait.php

492 lines
20 KiB
PHP
Raw Normal View History

2024-07-02 15:32:59 +08:00
<?php
/**
* Copyright 2019 Huawei Technologies Co.,Ltd.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
namespace Obs\Internal;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Obs\Internal\Common\CheckoutStream;
use Obs\Internal\Common\Model;
use Obs\Internal\Resource\Constants;
use Obs\Log\ObsLog;
use Obs\ObsException;
use Psr\Http\Message\StreamInterface;
trait GetResponseTrait
{
protected $exceptionResponseMode = true;
protected $chunkSize = 65536;
protected function isClientError(Response $response)
{
return $response->getStatusCode() >= 400 && $response->getStatusCode() < 500;
}
protected function parseXmlByType($searchPath, $key, &$value, $xml, $prefix)
{
$type = 'string';
if (isset($value['sentAs'])) {
$key = $value['sentAs'];
}
if ($searchPath === null) {
$searchPath = '//' . $prefix . $key;
}
if (isset($value['type'])) {
$type = $value['type'];
if ($type === 'array') {
$items = $value['items'];
if (isset($value['wrapper'])) {
$paths = explode('/', $searchPath);
$size = count($paths);
if ($size > 1) {
$end = $paths[$size - 1];
$paths[$size - 1] = $value['wrapper'];
$paths[] = $end;
$searchPath = implode('/', $paths) . '/' . $prefix;
}
}
$array = [];
if (!isset($value['data']['xmlFlattened'])) {
$pkey = isset($items['sentAs']) ? $items['sentAs'] : $items['name'];
$newSearchPath = $searchPath . '/' . $prefix . $pkey;
} else {
$pkey = $key;
$newSearchPath = $searchPath;
}
$result = $xml->xpath($newSearchPath);
if ($result && is_array($result)) {
foreach ($result as $subXml) {
$subXml = simplexml_load_string($subXml->asXML());
$subPrefix = $this->getXpathPrefix($subXml);
$array[] = $this->parseXmlByType(
'//' . $subPrefix . $pkey,
$pkey,
$items,
$subXml,
$subPrefix
);
}
}
return $array;
} elseif ($type === 'object') {
$properties = $value['properties'];
$array = [];
foreach ($properties as $pkey => $pvalue) {
$name = isset($pvalue['sentAs']) ? $pvalue['sentAs'] : $pkey;
$array[$pkey] = $this->parseXmlByType(
$searchPath . '/' . $prefix . $name,
$name,
$pvalue,
$xml,
$prefix
);
}
return $array;
} else {
// nothing handle
}
}
if ($result = $xml->xpath($searchPath)) {
if ($type === 'boolean') {
return strval($result[0]) !== 'false';
} elseif ($type === 'numeric' || $type === 'float') {
return floatval($result[0]);
} elseif ($type === 'int' || $type === 'integer') {
return intval($result[0]);
} else {
return strval($result[0]);
}
} else {
if ($type === 'boolean') {
return false;
} elseif ($type === 'numeric' || $type === 'float' || $type === 'int' || $type === 'integer') {
return null;
} else {
return '';
}
}
}
private function isJsonResponse($response)
{
return $response->getHeaderLine('content-type') === 'application/json';
}
private function parseCommonHeaders($model, $response)
{
$constants = Constants::selectConstants($this->signature);
foreach ($constants::COMMON_HEADERS as $key => $value) {
$model[$value] = $response->getHeaderLine($key);
}
}
protected function parseItems($responseParameters, $model, $response, $body)
{
$prefix = '';
$this->parseCommonHeaders($model, $response);
$closeBody = false;
try {
foreach ($responseParameters as $key => $value) {
if (isset($value['location'])) {
$location = $value['location'];
if ($location === 'header') {
$name = isset($value['sentAs']) ? $value['sentAs'] : $key;
$isSet = false;
if (isset($value['type'])) {
$type = $value['type'];
if ($type === 'object') {
$headers = $response->getHeaders();
$temp = [];
foreach ($headers as $headerName => $headerValue) {
if (stripos($headerName, $name) === 0) {
$metaKey = rawurldecode(substr($headerName, strlen($name)));
$temp[$metaKey] = rawurldecode($response->getHeaderLine($headerName));
}
}
$model[$key] = $temp;
$isSet = true;
} else {
if ($response->hasHeader($name)) {
if ($type === 'boolean') {
$model[$key] = ($response->getHeaderLine($name)) !== 'false';
$isSet = true;
} elseif ($type === 'numeric' || $type === 'float') {
$model[$key] = floatval($response->getHeaderLine($name));
$isSet = true;
} elseif ($type === 'int' || $type === 'integer') {
$model[$key] = intval($response->getHeaderLine($name));
$isSet = true;
} else {
// nothing handle
}
}
}
}
if (!$isSet) {
$model[$key] = rawurldecode($response->getHeaderLine($name));
}
} elseif ($location === 'xml' && $body !== null) {
if (!isset($xml)) {
$xml = simplexml_load_string($body->getContents());
if ($xml) {
$prefix = $this->getXpathPrefix($xml);
}
}
$closeBody = true;
$model[$key] = $this->parseXmlByType(null, $key, $value, $xml, $prefix);
} elseif ($location === 'body' && $body !== null) {
if (isset($value['type']) && $value['type'] === 'stream') {
$model[$key] = $body;
} elseif (isset($value['type']) && $value['type'] === 'json') {
$jsonBody = trim($body->getContents());
$data = json_decode($jsonBody, true);
if ($jsonBody && $data) {
if (is_array($data)) {
$model[$key] = $data;
} elseif (strlen($data)) {
ObsLog::commonLog(
ERROR,
"response body %s, and jsonToArray data is %s",
$body,
$data
);
} else {
// nothing handle
}
}
$closeBody = true;
} else {
$model[$key] = $body->getContents();
$closeBody = true;
}
} else {
// nothing handle
}
}
}
} finally {
if ($closeBody && $body !== null) {
$body->close();
}
}
}
private function writeFile($filePath, StreamInterface &$body)
{
$filePath = iconv('UTF-8', 'GBK', $filePath);
if (is_string($filePath) && $filePath !== '') {
$fp = null;
$dir = dirname($filePath);
try {
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
if ($fp = fopen($filePath, 'w')) {
while (!$body->eof()) {
$str = $body->read($this->chunkSize);
fwrite($fp, $str);
}
fflush($fp);
ObsLog::commonLog(DEBUG, "write file %s ok", $filePath);
} else {
ObsLog::commonLog(ERROR, "open file error,file path:%s", $filePath);
}
} finally {
if ($fp) {
fclose($fp);
}
$body->close();
$body = null;
}
}
}
private function parseXmlToException($body, $obsException)
{
try {
$xmlErrorBody = trim($body->getContents());
if ($xmlErrorBody) {
$xml = simplexml_load_string($xmlErrorBody);
if ($xml) {
$prefix = $this->getXpathPrefix($xml);
if ($tempXml = $xml->xpath('//' . $prefix . 'Code')) {
$obsException->setExceptionCode(strval($tempXml[0]));
}
if ($tempXml = $xml->xpath('//' . $prefix . 'RequestId')) {
$obsException->setRequestId(strval($tempXml[0]));
}
if ($tempXml = $xml->xpath('//' . $prefix . 'Message')) {
$obsException->setExceptionMessage(strval($tempXml[0]));
}
if ($tempXml = $xml->xpath('//' . $prefix . 'HostId')) {
$obsException->setHostId(strval($tempXml[0]));
}
}
}
} finally {
$body->close();
}
}
private function parseJsonToException($body, $obsException)
{
try {
$jsonErrorBody = trim($body->getContents());
if ($jsonErrorBody) {
$data = json_decode($jsonErrorBody, true);
if ($data && is_array($data)) {
if ($data['request_id']) {
$obsException->setRequestId(strval($data['request_id']));
}
if ($data['code']) {
$obsException->setExceptionCode(strval($data['code']));
}
if ($data['message']) {
$obsException->setExceptionMessage(strval($data['message']));
}
} elseif ($data && strlen($data)) {
ObsLog::commonLog(ERROR, "response body %s, and jsonToArray data is %s", $body, $data);
$obsException->setExceptionMessage("Invalid response datasince it is not json data");
} else {
// nothing handle
}
}
} finally {
$body->close();
}
}
private function parseJsonToModel($body, $model)
{
try {
$jsonErrorBody = trim($body->getContents());
if ($jsonErrorBody) {
$jsonArray = json_decode($jsonErrorBody, true);
if ($jsonArray && is_array($jsonArray)) {
if ($jsonArray['request_id']) {
$model['RequestId'] = strval($jsonArray['request_id']);
}
if ($jsonArray['code']) {
$model['Code'] = strval($jsonArray['code']);
}
if ($jsonArray['message']) {
$model['Message'] = strval($jsonArray['message']);
}
} elseif ($jsonArray && strlen($jsonArray)) {
ObsLog::commonLog(ERROR, "response body %s, and jsonToArray data is %s", $body, $jsonArray);
$model['Message'] = "Invalid response datasince it is not json data";
} else {
// nothing handle
}
}
} finally {
$body->close();
}
}
private function parseXmlToModel($body, $model)
{
try {
$xmlErrorBody = trim($body->getContents());
$xml = simplexml_load_string($xmlErrorBody);
if ($xmlErrorBody && $xml) {
$prefix = $this->getXpathPrefix($xml);
if ($tempXml = $xml->xpath('//' . $prefix . 'Code')) {
$model['Code'] = strval($tempXml[0]);
}
if ($tempXml = $xml->xpath('//' . $prefix . 'RequestId')) {
$model['RequestId'] = strval($tempXml[0]);
}
if ($tempXml = $xml->xpath('//' . $prefix . 'HostId')) {
$model['HostId'] = strval($tempXml[0]);
}
if ($tempXml = $xml->xpath('//' . $prefix . 'Resource')) {
$model['Resource'] = strval($tempXml[0]);
}
if ($tempXml = $xml->xpath('//' . $prefix . 'Message')) {
$model['Message'] = strval($tempXml[0]);
}
}
} finally {
$body->close();
}
}
protected function parseResponse(Model $model, Request $request, Response $response, array $requestConfig)
{
$statusCode = $response->getStatusCode();
$expectedLength = $response->getHeaderLine('content-length');
$responseContentType = $response->getHeaderLine('content-type');
$expectedLength = is_numeric($expectedLength) ? floatval($expectedLength) : null;
$body = new CheckoutStream($response->getBody(), $expectedLength);
if ($statusCode >= 300) {
if ($this->exceptionResponseMode) {
$obsException = new ObsException();
$obsException->setRequest($request);
$obsException->setResponse($response);
$obsException->setExceptionType($this->isClientError($response) ? 'client' : 'server');
if ($responseContentType === 'application/json') {
$this->parseJsonToException($body, $obsException);
} else {
$this->parseXmlToException($body, $obsException);
}
throw $obsException;
} else {
$this->parseCommonHeaders($model, $response);
if ($responseContentType === 'application/json') {
$this->parseJsonToModel($body, $model);
} else {
$this->parseXmlToModel($body, $model);
}
}
} else {
if (!empty($model)) {
foreach ($model as $key => $value) {
if ($key === 'method') {
continue;
}
if (isset($value['type']) && $value['type'] === 'file') {
$this->writeFile($value['value'], $body);
}
$model[$key] = $value['value'];
}
}
if (isset($requestConfig['responseParameters'])) {
$responseParameters = $requestConfig['responseParameters'];
if (isset($responseParameters['type']) && $responseParameters['type'] === 'object') {
$responseParameters = $responseParameters['properties'];
}
$this->parseItems($responseParameters, $model, $response, $body);
}
}
$model['HttpStatusCode'] = $statusCode;
$model['Reason'] = $response->getReasonPhrase();
}
protected function getXpathPrefix($xml)
{
$namespaces = $xml->getDocNamespaces();
if (isset($namespaces[''])) {
$xml->registerXPathNamespace('ns', $namespaces['']);
$prefix = 'ns:';
} else {
$prefix = '';
}
return $prefix;
}
protected function buildException(Request $request, RequestException $exception, $message)
{
$response = $exception->hasResponse() ? $exception->getResponse() : null;
$obsException = new ObsException($message ? $message : $exception->getMessage());
$obsException->setExceptionType('client');
$obsException->setRequest($request);
if ($response) {
$obsException->setResponse($response);
$obsException->setExceptionType($this->isClientError($response) ? 'client' : 'server');
if ($this->isJsonResponse($response)) {
$this->parseJsonToException($response->getBody(), $obsException);
} else {
$this->parseXmlToException($response->getBody(), $obsException);
}
if ($obsException->getRequestId() === null) {
$prefix = strcasecmp($this->signature, 'obs') === 0 ? 'x-obs-' : 'x-amz-';
$requestId = $response->getHeaderLine($prefix . 'request-id');
$obsException->setRequestId($requestId);
}
}
return $obsException;
}
protected function parseExceptionAsync(Request $request, RequestException $exception, $message = null)
{
return $this->buildException($request, $exception, $message);
}
protected function parseException(Model $model, Request $request, RequestException $exception, $message = null)
{
$response = $exception->hasResponse() ? $exception->getResponse() : null;
if ($this->exceptionResponseMode) {
throw $this->buildException($request, $exception, $message);
} else {
if ($response) {
$model['HttpStatusCode'] = $response->getStatusCode();
$model['Reason'] = $response->getReasonPhrase();
$this->parseXmlToModel($response->getBody(), $model);
} else {
$model['HttpStatusCode'] = -1;
$model['Message'] = $exception->getMessage();
}
}
}
}