| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815 |
- <?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\Psr7;
- use GuzzleHttp\Client;
- use GuzzleHttp\Exception\ConnectException;
- use GuzzleHttp\Exception\RequestException;
- use GuzzleHttp\Psr7\Request;
- use GuzzleHttp\Psr7\Response;
- use Obs\Internal\Common\Model;
- use Obs\Internal\Resource\Constants;
- use Obs\Internal\Resource\V2Constants;
- use Obs\Internal\Signature\DefaultSignature;
- use Obs\Internal\Signature\V4Signature;
- use Obs\Log\ObsLog;
- use Obs\ObsException;
- use Obs\ObsClient;
- use Psr\Http\Message\StreamInterface;
- const INVALID_HTTP_METHOD_MSG =
- "Method param must be specified, allowed values: GET | PUT | HEAD | POST | DELETE | OPTIONS";
- trait SendRequestTrait
- {
- protected $ak;
- protected $sk;
- protected $securityToken = false;
- protected $endpoint = '';
- protected $pathStyle = false;
- protected $region = 'region';
- protected $signature = 'obs';
- protected $sslVerify = false;
- protected $maxRetryCount = 3;
- protected $timeout = 0;
- protected $socketTimeout = 60;
- protected $connectTimeout = 60;
- protected $isCname = false;
- /** @var Client */
- protected $httpClient;
- public function createSignedUrl(array $args = [])
- {
- if (strcasecmp($this->signature, 'v4') === 0) {
- return $this->createV4SignedUrl($args);
- }
- return $this->createCommonSignedUrl($this->signature, $args);
- }
- public function createV2SignedUrl(array $args = [])
- {
- return $this->createCommonSignedUrl('v2', $args);
- }
- private function createCommonSignedUrl(string $signature, array $args = [])
- {
- if (!isset($args['Method'])) {
- $obsException = new ObsException(INVALID_HTTP_METHOD_MSG);
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- $method = strval($args['Method']);
- $bucketName = isset($args['Bucket']) ? strval($args['Bucket']) : null;
- $objectKey = isset($args['Key']) ? strval($args['Key']) : null;
- $specialParam = isset($args['SpecialParam']) ? strval($args['SpecialParam']) : null;
- $expires = isset($args['Expires']) && is_numeric($args['Expires']) ? intval($args['Expires']) : 300;
- $headers = [];
- if (isset($args['Headers']) && is_array($args['Headers'])) {
- foreach ($args['Headers'] as $key => $val) {
- if (is_string($key) && $key !== '') {
- $headers[$key] = $val;
- }
- }
- }
- $queryParams = [];
- if (isset($args['QueryParams']) && is_array($args['QueryParams'])) {
- foreach ($args['QueryParams'] as $key => $val) {
- if (is_string($key) && $key !== '') {
- $queryParams[$key] = $val;
- }
- }
- }
- $constants = Constants::selectConstants($signature);
- if ($this->securityToken && !isset($queryParams[$constants::SECURITY_TOKEN_HEAD])) {
- $queryParams[$constants::SECURITY_TOKEN_HEAD] = $this->securityToken;
- }
- $sign = new DefaultSignature(
- $this->ak,
- $this->sk,
- $this->pathStyle,
- $this->endpoint,
- $method,
- $this->signature,
- $this->securityToken,
- $this->isCname
- );
- $url = parse_url($this->endpoint);
- $host = $url['host'];
- $result = '';
- if ($bucketName) {
- if ($this->pathStyle) {
- $result = '/' . $bucketName;
- } else {
- $host = $this->isCname ? $host : $bucketName . '.' . $host;
- }
- }
- $headers['Host'] = $host;
- if ($objectKey) {
- $objectKey = $sign->urlencodeWithSafe($objectKey);
- $result .= '/' . $objectKey;
- }
- $result .= '?';
- if ($specialParam) {
- $queryParams[$specialParam] = '';
- }
- $queryParams[$constants::TEMPURL_AK_HEAD] = $this->ak;
- if (!is_numeric($expires) || $expires < 0) {
- $expires = 300;
- }
- $expires = intval($expires) + intval(microtime(true));
- $queryParams['Expires'] = strval($expires);
- $queryParamsResult = [];
- foreach ($queryParams as $key => $val) {
- $key = $sign->urlencodeWithSafe($key);
- $val = $sign->urlencodeWithSafe($val);
- $queryParamsResult[$key] = $val;
- $result .= $key;
- if ($val) {
- $result .= '=' . $val;
- }
- $result .= '&';
- }
- $canonicalstring = $sign->makeCanonicalstring(
- $method,
- $headers,
- $queryParamsResult,
- $bucketName,
- $objectKey,
- $expires
- );
- $signatureContent = base64_encode(hash_hmac('sha1', $canonicalstring, $this->sk, true));
- $result .= 'Signature=' . $sign->urlencodeWithSafe($signatureContent);
- $model = new Model();
- $model['ActualSignedRequestHeaders'] = $headers;
- $defaultPort = strtolower($url['scheme']) === 'https' ? '443' : '80';
- $port = isset($url['port']) ? $url['port'] : $defaultPort;
- $model['SignedUrl'] = $url['scheme'] . '://' . $host . ':' . $port . $result;
- return $model;
- }
- public function createV4SignedUrl(array $args = [])
- {
- if (!isset($args['Method'])) {
- $obsException = new ObsException(INVALID_HTTP_METHOD_MSG);
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- $method = strval($args['Method']);
- $bucketName = isset($args['Bucket']) ? strval($args['Bucket']) : null;
- $objectKey = isset($args['Key']) ? strval($args['Key']) : null;
- $specialParam = isset($args['SpecialParam']) ? strval($args['SpecialParam']) : null;
- $expires = isset($args['Expires']) && is_numeric($args['Expires']) ? intval($args['Expires']) : 300;
- $headers = [];
- if (isset($args['Headers']) && is_array($args['Headers'])) {
- foreach ($args['Headers'] as $key => $val) {
- if (is_string($key) && $key !== '') {
- $headers[$key] = $val;
- }
- }
- }
- $queryParams = [];
- if (isset($args['QueryParams']) && is_array($args['QueryParams'])) {
- foreach ($args['QueryParams'] as $key => $val) {
- if (is_string($key) && $key !== '') {
- $queryParams[$key] = $val;
- }
- }
- }
- if ($this->securityToken && !isset($queryParams['x-amz-security-token'])) {
- $queryParams['x-amz-security-token'] = $this->securityToken;
- }
- $utcTimeZone = new \DateTimeZone('UTC');
- $v4 = new V4Signature(
- $this->ak,
- $this->sk,
- $this->pathStyle,
- $this->endpoint,
- $this->region,
- $method,
- $utcTimeZone,
- $this->signature,
- $this->securityToken,
- $this->isCname
- );
- $url = parse_url($this->endpoint);
- $host = $url['host'];
- $result = '';
- if ($bucketName) {
- if ($this->pathStyle) {
- $result = '/' . $bucketName;
- } else {
- $host = $this->isCname ? $host : $bucketName . '.' . $host;
- }
- }
- $headers['Host'] = $host;
- if ($objectKey) {
- $objectKey = $v4->urlencodeWithSafe($objectKey);
- $result .= '/' . $objectKey;
- }
- $result .= '?';
- if ($specialParam) {
- $queryParams[$specialParam] = '';
- }
- if (!is_numeric($expires) || $expires < 0) {
- $expires = 300;
- }
- $expires = strval($expires);
- $date = $headers['date'];
- if (!isset($date)) {
- $date = $headers['Date'];
- }
- if (!isset($date)) {
- $date = null;
- }
- $timestamp = time();
- if (isset($date)) {
- $timestamp = date_create_from_format('D, d M Y H:i:s \G\M\T', $date, new \DateTimeZone('UTC'))->getTimestamp();
- }
- $longDate = gmdate('Ymd\THis\Z', $timestamp);
- $shortDate = substr($longDate, 0, 8);
- $headers['host'] = $host;
- if (isset($url['port'])) {
- $port = $url['port'];
- if ($port !== 443 && $port !== 80) {
- $headers['host'] = $headers['host'] . ':' . $port;
- }
- }
- $signedHeaders = $v4->getSignedHeaders($headers);
- $queryParams['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
- $queryParams['X-Amz-Credential'] = $v4->getCredential($shortDate);
- $queryParams['X-Amz-Date'] = $longDate;
- $queryParams['X-Amz-Expires'] = $expires;
- $queryParams['X-Amz-SignedHeaders'] = $signedHeaders;
- $queryParamsResult = [];
- foreach ($queryParams as $key => $val) {
- $key = rawurlencode($key);
- $val = rawurlencode($val);
- $queryParamsResult[$key] = $val;
- $result .= $key;
- if ($val) {
- $result .= '=' . $val;
- }
- $result .= '&';
- }
- $canonicalstring = $v4->makeCanonicalstring(
- $method,
- $headers,
- $queryParamsResult,
- $bucketName,
- $objectKey,
- $signedHeaders,
- 'UNSIGNED-PAYLOAD'
- );
- $signatureContent = $v4->getSignature($canonicalstring, $longDate, $shortDate);
- $result .= 'X-Amz-Signature=' . $v4->urlencodeWithSafe($signatureContent);
- $model = new Model();
- $model['ActualSignedRequestHeaders'] = $headers;
- $defaultPort = strtolower($url['scheme']) === 'https' ? '443' : '80';
- $port = isset($url['port']) ? $url['port'] : $defaultPort;
- $model['SignedUrl'] = $url['scheme'] . '://' . $host . ':' . $port . $result;
- return $model;
- }
- public function createPostSignature(array $args = [])
- {
- if (strcasecmp($this->signature, 'v4') === 0) {
- return $this->createV4PostSignature($args);
- }
- $bucketName = isset($args['Bucket']) ? strval($args['Bucket']) : null;
- $objectKey = isset($args['Key']) ? strval($args['Key']) : null;
- $expires = isset($args['Expires']) && is_numeric($args['Expires']) ? intval($args['Expires']) : 300;
- $formParams = [];
- if (isset($args['FormParams']) && is_array($args['FormParams'])) {
- foreach ($args['FormParams'] as $key => $val) {
- $formParams[$key] = $val;
- }
- }
- $constants = Constants::selectConstants($this->signature);
- if ($this->securityToken && !isset($formParams[$constants::SECURITY_TOKEN_HEAD])) {
- $formParams[$constants::SECURITY_TOKEN_HEAD] = $this->securityToken;
- }
- $timestamp = time();
- $expires = gmdate('Y-m-d\TH:i:s\Z', $timestamp + $expires);
- if ($bucketName) {
- $formParams['bucket'] = $bucketName;
- }
- if ($objectKey) {
- $formParams['key'] = $objectKey;
- }
- $policy = [];
- $policy[] = '{"expiration":"';
- $policy[] = $expires;
- $policy[] = '", "conditions":[';
- $matchAnyBucket = true;
- $matchAnyKey = true;
- $conditionAllowKeys = ['acl', 'bucket', 'key', 'success_action_redirect', 'redirect', 'success_action_status'];
- foreach ($formParams as $key => $val) {
- if ($key) {
- $key = strtolower(strval($key));
- if ($key === 'bucket') {
- $matchAnyBucket = false;
- } elseif ($key === 'key') {
- $matchAnyKey = false;
- } else {
- // nothing handle
- }
- if (!in_array($key, Constants::ALLOWED_REQUEST_HTTP_HEADER_METADATA_NAMES)
- && strpos($key, $constants::HEADER_PREFIX) !== 0
- && !in_array($key, $conditionAllowKeys)
- ) {
- $key = $constants::METADATA_PREFIX . $key;
- }
- $policy[] = '{"';
- $policy[] = $key;
- $policy[] = '":"';
- $policy[] = $val !== null ? strval($val) : '';
- $policy[] = '"},';
- }
- }
- if ($matchAnyBucket) {
- $policy[] = '["starts-with", "$bucket", ""],';
- }
- if ($matchAnyKey) {
- $policy[] = '["starts-with", "$key", ""],';
- }
- $policy[] = ']}';
- $originPolicy = implode('', $policy);
- $policy = base64_encode($originPolicy);
- $signatureContent = base64_encode(hash_hmac('sha1', $policy, $this->sk, true));
- $model = new Model();
- $model['OriginPolicy'] = $originPolicy;
- $model['Policy'] = $policy;
- $model['Signature'] = $signatureContent;
- return $model;
- }
- public function createV4PostSignature(array $args = [])
- {
- $bucketName = isset($args['Bucket']) ? strval($args['Bucket']) : null;
- $objectKey = isset($args['Key']) ? strval($args['Key']) : null;
- $expires = isset($args['Expires']) && is_numeric($args['Expires']) ? intval($args['Expires']) : 300;
- $formParams = [];
- if (isset($args['FormParams']) && is_array($args['FormParams'])) {
- foreach ($args['FormParams'] as $key => $val) {
- $formParams[$key] = $val;
- }
- }
- if ($this->securityToken && !isset($formParams['x-amz-security-token'])) {
- $formParams['x-amz-security-token'] = $this->securityToken;
- }
- $timestamp = time();
- $longDate = gmdate('Ymd\THis\Z', $timestamp);
- $shortDate = substr($longDate, 0, 8);
- $credential = sprintf('%s/%s/%s/s3/aws4_request', $this->ak, $shortDate, $this->region);
- $expires = gmdate('Y-m-d\TH:i:s\Z', $timestamp + $expires);
- $formParams['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
- $formParams['X-Amz-Date'] = $longDate;
- $formParams['X-Amz-Credential'] = $credential;
- if ($bucketName) {
- $formParams['bucket'] = $bucketName;
- }
- if ($objectKey) {
- $formParams['key'] = $objectKey;
- }
- $policy = [];
- $policy[] = '{"expiration":"';
- $policy[] = $expires;
- $policy[] = '", "conditions":[';
- $matchAnyBucket = true;
- $matchAnyKey = true;
- $conditionAllowKeys = ['acl', 'bucket', 'key', 'success_action_redirect', 'redirect', 'success_action_status'];
- foreach ($formParams as $key => $val) {
- if ($key) {
- $key = strtolower(strval($key));
- if ($key === 'bucket') {
- $matchAnyBucket = false;
- }
- if ($key === 'key') {
- $matchAnyKey = false;
- }
- if (!in_array($key, Constants::ALLOWED_REQUEST_HTTP_HEADER_METADATA_NAMES)
- && strpos($key, V2Constants::HEADER_PREFIX) !== 0
- && !in_array($key, $conditionAllowKeys)
- ) {
- $key = V2Constants::METADATA_PREFIX . $key;
- }
- $policy[] = '{"';
- $policy[] = $key;
- $policy[] = '":"';
- $policy[] = $val !== null ? strval($val) : '';
- $policy[] = '"},';
- }
- }
- if ($matchAnyBucket) {
- $policy[] = '["starts-with", "$bucket", ""],';
- }
- if ($matchAnyKey) {
- $policy[] = '["starts-with", "$key", ""],';
- }
- $policy[] = ']}';
- $originPolicy = implode('', $policy);
- $policy = base64_encode($originPolicy);
- $dateKey = hash_hmac('sha256', $shortDate, 'AWS4' . $this->sk, true);
- $regionKey = hash_hmac('sha256', $this->region, $dateKey, true);
- $serviceKey = hash_hmac('sha256', 's3', $regionKey, true);
- $signingKey = hash_hmac('sha256', 'aws4_request', $serviceKey, true);
- $signatureContent = hash_hmac('sha256', $policy, $signingKey);
- $model = new Model();
- $model['OriginPolicy'] = $originPolicy;
- $model['Policy'] = $policy;
- $model['Algorithm'] = $formParams['X-Amz-Algorithm'];
- $model['Credential'] = $formParams['X-Amz-Credential'];
- $model['Date'] = $formParams['X-Amz-Date'];
- $model['Signature'] = $signatureContent;
- return $model;
- }
- public function __call($originMethod, $args)
- {
- $method = $originMethod;
- $contents = Constants::selectRequestResource($this->signature);
- $resource = &$contents::$resourceArray;
- $async = false;
- if (strpos($method, 'Async') === (strlen($method) - 5)) {
- $method = substr($method, 0, strlen($method) - 5);
- $async = true;
- }
- if (isset($resource['aliases'][$method])) {
- $method = $resource['aliases'][$method];
- }
- $method = lcfirst($method);
- $operation = isset($resource['operations'][$method]) ?
- $resource['operations'][$method] : null;
- if (!$operation) {
- ObsLog::commonLog(WARNING, 'unknow method ' . $originMethod);
- $obsException = new ObsException('unknow method ' . $originMethod);
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- $start = microtime(true);
- if (!$async) {
- ObsLog::commonLog(INFO, 'enter method ' . $originMethod . '...');
- $model = new Model();
- $model['method'] = $method;
- $params = empty($args) ? [] : $args[0];
- $this->checkMimeType($method, $params);
- $this->doRequest($model, $operation, $params);
- ObsLog::commonLog(INFO, 'obsclient cost ' . round(microtime(true) - $start, 3) * 1000 . ' ms to execute ' . $originMethod);
- unset($model['method']);
- return $model;
- } else {
- if (empty($args) || !(is_callable($callback = $args[count($args) - 1]))) {
- ObsLog::commonLog(WARNING, 'async method ' . $originMethod . ' must pass a CallbackInterface as param');
- $obsException = new ObsException('async method ' . $originMethod . ' must pass a CallbackInterface as param');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- ObsLog::commonLog(INFO, 'enter method ' . $originMethod . '...');
- $params = count($args) === 1 ? [] : $args[0];
- $this->checkMimeType($method, $params);
- $model = new Model();
- $model['method'] = $method;
- return $this->doRequestAsync($model, $operation, $params, $callback, $start, $originMethod);
- }
- }
- private function hasContentType(&$params)
- {
- return isset($params['ContentType']) && $params['ContentType'] !== null;
- }
- private function checkMimeType($method, &$params)
- {
- // fix bug that guzzlehttp lib will add the content-type if not set
- $uploadMehods = array('putObject', 'initiateMultipartUpload', 'uploadPart');
- $hasContentTypeFlag = $this->hasContentType($params);
- if (in_array($method, $uploadMehods) && !$hasContentTypeFlag) {
- if (isset($params['Key'])) {
- try {
- $params['ContentType'] = Psr7\mimetype_from_filename($params['Key']);
- } catch (\Throwable $e) {
- $params['ContentType'] = Psr7\MimeType::fromFilename($params['Key']);
- }
- }
- if (!$hasContentTypeFlag && isset($params['SourceFile'])) {
- try {
- $params['ContentType'] = Psr7\mimetype_from_filename($params['SourceFile']);
- } catch (\Throwable $e) {
- $params['ContentType'] = Psr7\MimeType::fromFilename($params['SourceFile']);
- }
- }
- if (!$hasContentTypeFlag) {
- $params['ContentType'] = 'binary/octet-stream';
- }
- }
- }
- protected function makeRequest($model, &$operation, $params, $endpoint = null)
- {
- if ($endpoint === null) {
- $endpoint = $this->endpoint;
- }
- $utcTimeZone = new \DateTimeZone('UTC');
- $signatureInterface = strcasecmp($this->signature, 'v4') === 0
- ? new V4Signature(
- $this->ak,
- $this->sk,
- $this->pathStyle,
- $endpoint,
- $this->region,
- $model['method'],
- $this->signature,
- $utcTimeZone,
- $this->securityToken,
- $this->isCname
- )
- : new DefaultSignature(
- $this->ak,
- $this->sk,
- $this->pathStyle,
- $endpoint,
- $model['method'],
- $this->signature,
- $this->securityToken,
- $this->isCname
- );
- $authResult = $signatureInterface->doAuth($operation, $params, $model);
- $httpMethod = $authResult['method'];
- ObsLog::commonLog(DEBUG, 'perform ' . strtolower($httpMethod) . ' request with url ' . $authResult['requestUrl']);
- ObsLog::commonLog(DEBUG, 'cannonicalRequest:' . $authResult['cannonicalRequest']);
- ObsLog::commonLog(DEBUG, 'request headers ' . var_export($authResult['headers'], true));
- $authResult['headers']['User-Agent'] = ObsClient::getDefaultUserAgent();
- if ($model['method'] === 'putObject') {
- $model['ObjectURL'] = ['value' => $authResult['requestUrl']];
- }
- return new Request($httpMethod, $authResult['requestUrl'], $authResult['headers'], $authResult['body']);
- }
- protected function doRequest($model, &$operation, $params, $endpoint = null)
- {
- $request = $this->makeRequest($model, $operation, $params, $endpoint);
- $this->sendRequest($model, $operation, $params, $request);
- }
- protected function sendRequest($model, &$operation, $params, $request, $requestCount = 1)
- {
- $start = microtime(true);
- $saveAsStream = false;
- if (isset($operation['stream']) && $operation['stream']) {
- $saveAsStream = isset($params['SaveAsStream']) ? $params['SaveAsStream'] : false;
- if (isset($params['SaveAsFile'])) {
- if ($saveAsStream) {
- $obsException = new ObsException('SaveAsStream cannot be used with SaveAsFile together');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- $saveAsStream = true;
- }
- if (isset($params['FilePath'])) {
- if ($saveAsStream) {
- $obsException = new ObsException('SaveAsStream cannot be used with FilePath together');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- $saveAsStream = true;
- }
- if (isset($params['SaveAsFile']) && isset($params['FilePath'])) {
- $obsException = new ObsException('SaveAsFile cannot be used with FilePath together');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- }
- $promise = $this->httpClient->sendAsync($request, ['stream' => $saveAsStream])->then(
- function (Response $response) use ($model, $operation, $params, $request, $requestCount, $start) {
- ObsLog::commonLog(INFO, 'http request cost ' . round(microtime(true) - $start, 3) * 1000 . ' ms');
- $statusCode = $response->getStatusCode();
- $readable = isset($params['Body']) && ($params['Body'] instanceof StreamInterface || is_resource($params['Body']));
- $isRetryRequest = $statusCode >= 300 && $statusCode < 400 && $statusCode !== 304 && !$readable && $requestCount <= $this->maxRetryCount;
- $location = $response->getHeaderLine('location');
- if ($isRetryRequest && $location) {
- $url = parse_url($this->endpoint);
- $newUrl = parse_url($location);
- $scheme = (isset($newUrl['scheme']) ? $newUrl['scheme'] : $url['scheme']);
- $defaultPort = strtolower($scheme) === 'https' ? '443' : '80';
- $port = isset($newUrl['port']) ? $newUrl['port'] : $defaultPort;
- $newEndpoint = $scheme . '://' . $newUrl['host'] . ':' . $port;
- $this->doRequest($model, $operation, $params, $newEndpoint);
- return;
- }
- $this->parseResponse($model, $request, $response, $operation);
- },
- function (RequestException $exception) use ($model, $operation, $params, $request, $requestCount, $start) {
- ObsLog::commonLog(INFO, 'http request cost ' . round(microtime(true) - $start, 3) * 1000 . ' ms');
- $message = null;
- if ($exception instanceof ConnectException) {
- if ($requestCount <= $this->maxRetryCount) {
- $this->sendRequest($model, $operation, $params, $request, $requestCount + 1);
- return;
- } else {
- $message = 'Exceeded retry limitation, max retry count:' . $this->maxRetryCount . ', error message:' . $exception->getMessage();
- }
- }
- $this->parseException($model, $request, $exception, $message);
- });
- $promise->wait();
- }
- protected function doRequestAsync($model, &$operation, $params, $callback, $startAsync, $originMethod, $endpoint = null)
- {
- $request = $this->makeRequest($model, $operation, $params, $endpoint);
- return $this->sendRequestAsync($model, $operation, $params, $callback, $startAsync, $originMethod, $request);
- }
- protected function sendRequestAsync($model, &$operation, $params, $callback, $startAsync, $originMethod, $request, $requestCount = 1)
- {
- $start = microtime(true);
- $saveAsStream = false;
- if (isset($operation['stream']) && $operation['stream']) {
- $saveAsStream = isset($params['SaveAsStream']) ? $params['SaveAsStream'] : false;
- if ($saveAsStream) {
- if (isset($params['SaveAsFile'])) {
- $obsException = new ObsException('SaveAsStream cannot be used with SaveAsFile together');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- if (isset($params['FilePath'])) {
- $obsException = new ObsException('SaveAsStream cannot be used with FilePath together');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- }
- if (isset($params['SaveAsFile']) && isset($params['FilePath'])) {
- $obsException = new ObsException('SaveAsFile cannot be used with FilePath together');
- $obsException->setExceptionType('client');
- throw $obsException;
- }
- }
- return $this->httpClient->sendAsync($request, ['stream' => $saveAsStream])->then(
- function (Response $response) use ($model, $operation, $params, $callback, $startAsync, $originMethod, $request, $start) {
- ObsLog::commonLog(INFO, 'http request cost ' . round(microtime(true) - $start, 3) * 1000 . ' ms');
- $statusCode = $response->getStatusCode();
- $readable = isset($params['Body']) && ($params['Body'] instanceof StreamInterface || is_resource($params['Body']));
- if ($statusCode === 307 && !$readable) {
- $location = $response->getHeaderLine('location');
- if ($location) {
- $url = parse_url($this->endpoint);
- $newUrl = parse_url($location);
- $scheme = (isset($newUrl['scheme']) ? $newUrl['scheme'] : $url['scheme']);
- $defaultPort = strtolower($scheme) === 'https' ? '443' : '80';
- $port = isset($newUrl['port']) ? $newUrl['port'] : $defaultPort;
- $newEndpoint = $scheme . '://' . $newUrl['host'] . ':' . $port;
- return $this->doRequestAsync($model, $operation, $params, $callback, $startAsync, $originMethod, $newEndpoint);
- }
- }
- $this->parseResponse($model, $request, $response, $operation);
- ObsLog::commonLog(INFO, 'obsclient cost ' . round(microtime(true) - $startAsync, 3) * 1000 . ' ms to execute ' . $originMethod);
- unset($model['method']);
- $callback(null, $model);
- },
- function (RequestException $exception) use ($model, $operation, $params, $callback, $startAsync, $originMethod, $request, $start, $requestCount) {
- ObsLog::commonLog(INFO, 'http request cost ' . round(microtime(true) - $start, 3) * 1000 . ' ms');
- $message = null;
- if ($exception instanceof ConnectException) {
- if ($requestCount <= $this->maxRetryCount) {
- return $this->sendRequestAsync($model, $operation, $params, $callback, $startAsync, $originMethod, $request, $requestCount + 1);
- } else {
- $message = 'Exceeded retry limitation, max retry count:' . $this->maxRetryCount . ', error message:' . $exception->getMessage();
- }
- }
- $obsException = $this->parseExceptionAsync($request, $exception, $message);
- ObsLog::commonLog(INFO, 'obsclient cost ' . round(microtime(true) - $startAsync, 3) * 1000 . ' ms to execute ' . $originMethod);
- $callback($obsException, null);
- }
- );
- }
- }
|