summaryrefslogtreecommitdiff
path: root/vendor/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php')
-rw-r--r--vendor/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php307
1 files changed, 307 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php b/vendor/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php
new file mode 100644
index 0000000..dbd925a
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php
@@ -0,0 +1,307 @@
+<?php
+namespace Aws\Api\Serializer;
+
+use Aws\Api\MapShape;
+use Aws\Api\Service;
+use Aws\Api\Operation;
+use Aws\Api\Shape;
+use Aws\Api\StructureShape;
+use Aws\Api\TimestampShape;
+use Aws\CommandInterface;
+use Aws\EndpointV2\EndpointProviderV2;
+use Aws\EndpointV2\EndpointV2SerializerTrait;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\Request;
+use GuzzleHttp\Psr7\Uri;
+use GuzzleHttp\Psr7\UriResolver;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Serializes HTTP locations like header, uri, payload, etc...
+ * @internal
+ */
+abstract class RestSerializer
+{
+ use EndpointV2SerializerTrait;
+
+ /** @var Service */
+ private $api;
+
+ /** @var Uri */
+ private $endpoint;
+
+ /**
+ * @param Service $api Service API description
+ * @param string $endpoint Endpoint to connect to
+ */
+ public function __construct(Service $api, $endpoint)
+ {
+ $this->api = $api;
+ $this->endpoint = Psr7\Utils::uriFor($endpoint);
+ }
+
+ /**
+ * @param CommandInterface $command Command to serialize into a request.
+ * @param $endpointProvider Provider used for dynamic endpoint resolution.
+ * @param $clientArgs Client arguments used for dynamic endpoint resolution.
+ *
+ * @return RequestInterface
+ */
+ public function __invoke(
+ CommandInterface $command,
+ $endpointProvider = null,
+ $clientArgs = null
+ )
+ {
+ $operation = $this->api->getOperation($command->getName());
+ $commandArgs = $command->toArray();
+ $opts = $this->serialize($operation, $commandArgs);
+ $headers = isset($opts['headers']) ? $opts['headers'] : [];
+
+ if ($endpointProvider instanceof EndpointProviderV2) {
+ $this->setRequestOptions(
+ $endpointProvider,
+ $command,
+ $operation,
+ $commandArgs,
+ $clientArgs,
+ $headers
+ );
+ $this->endpoint = new Uri($this->endpoint);
+ }
+ $uri = $this->buildEndpoint($operation, $commandArgs, $opts);
+
+ return new Request(
+ $operation['http']['method'],
+ $uri,
+ $headers,
+ isset($opts['body']) ? $opts['body'] : null
+ );
+ }
+
+ /**
+ * Modifies a hash of request options for a payload body.
+ *
+ * @param StructureShape $member Member to serialize
+ * @param array $value Value to serialize
+ * @param array $opts Request options to modify.
+ */
+ abstract protected function payload(
+ StructureShape $member,
+ array $value,
+ array &$opts
+ );
+
+ private function serialize(Operation $operation, array $args)
+ {
+ $opts = [];
+ $input = $operation->getInput();
+
+ // Apply the payload trait if present
+ if ($payload = $input['payload']) {
+ $this->applyPayload($input, $payload, $args, $opts);
+ }
+
+ foreach ($args as $name => $value) {
+ if ($input->hasMember($name)) {
+ $member = $input->getMember($name);
+ $location = $member['location'];
+ if (!$payload && !$location) {
+ $bodyMembers[$name] = $value;
+ } elseif ($location == 'header') {
+ $this->applyHeader($name, $member, $value, $opts);
+ } elseif ($location == 'querystring') {
+ $this->applyQuery($name, $member, $value, $opts);
+ } elseif ($location == 'headers') {
+ $this->applyHeaderMap($name, $member, $value, $opts);
+ }
+ }
+ }
+
+ if (isset($bodyMembers)) {
+ $this->payload($operation->getInput(), $bodyMembers, $opts);
+ } else if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) {
+ $this->payload($operation->getInput(), [], $opts);
+ }
+
+ return $opts;
+ }
+
+ private function applyPayload(StructureShape $input, $name, array $args, array &$opts)
+ {
+ if (!isset($args[$name])) {
+ return;
+ }
+
+ $m = $input->getMember($name);
+
+ if ($m['streaming'] ||
+ ($m['type'] == 'string' || $m['type'] == 'blob')
+ ) {
+ // Streaming bodies or payloads that are strings are
+ // always just a stream of data.
+ $opts['body'] = Psr7\Utils::streamFor($args[$name]);
+ return;
+ }
+
+ $this->payload($m, $args[$name], $opts);
+ }
+
+ private function applyHeader($name, Shape $member, $value, array &$opts)
+ {
+ if ($member->getType() === 'timestamp') {
+ $timestampFormat = !empty($member['timestampFormat'])
+ ? $member['timestampFormat']
+ : 'rfc822';
+ $value = TimestampShape::format($value, $timestampFormat);
+ } elseif ($member->getType() === 'boolean') {
+ $value = $value ? 'true' : 'false';
+ }
+
+ if ($member['jsonvalue']) {
+ $value = json_encode($value);
+ if (empty($value) && JSON_ERROR_NONE !== json_last_error()) {
+ throw new \InvalidArgumentException('Unable to encode the provided value'
+ . ' with \'json_encode\'. ' . json_last_error_msg());
+ }
+
+ $value = base64_encode($value);
+ }
+
+ $opts['headers'][$member['locationName'] ?: $name] = $value;
+ }
+
+ /**
+ * Note: This is currently only present in the Amazon S3 model.
+ */
+ private function applyHeaderMap($name, Shape $member, array $value, array &$opts)
+ {
+ $prefix = $member['locationName'];
+ foreach ($value as $k => $v) {
+ $opts['headers'][$prefix . $k] = $v;
+ }
+ }
+
+ private function applyQuery($name, Shape $member, $value, array &$opts)
+ {
+ if ($member instanceof MapShape) {
+ $opts['query'] = isset($opts['query']) && is_array($opts['query'])
+ ? $opts['query'] + $value
+ : $value;
+ } elseif ($value !== null) {
+ $type = $member->getType();
+ if ($type === 'boolean') {
+ $value = $value ? 'true' : 'false';
+ } elseif ($type === 'timestamp') {
+ $timestampFormat = !empty($member['timestampFormat'])
+ ? $member['timestampFormat']
+ : 'iso8601';
+ $value = TimestampShape::format($value, $timestampFormat);
+ }
+
+ $opts['query'][$member['locationName'] ?: $name] = $value;
+ }
+ }
+
+ private function buildEndpoint(Operation $operation, array $args, array $opts)
+ {
+ // Create an associative array of variable definitions used in expansions
+ $varDefinitions = $this->getVarDefinitions($operation, $args);
+
+ $relative = preg_replace_callback(
+ '/\{([^\}]+)\}/',
+ function (array $matches) use ($varDefinitions) {
+ $isGreedy = substr($matches[1], -1, 1) == '+';
+ $k = $isGreedy ? substr($matches[1], 0, -1) : $matches[1];
+ if (!isset($varDefinitions[$k])) {
+ return '';
+ }
+
+ if ($isGreedy) {
+ return str_replace('%2F', '/', rawurlencode($varDefinitions[$k]));
+ }
+
+ return rawurlencode($varDefinitions[$k]);
+ },
+ $operation['http']['requestUri']
+ );
+
+ // Add the query string variables or appending to one if needed.
+ if (!empty($opts['query'])) {
+ $relative = $this->appendQuery($opts['query'], $relative);
+ }
+
+ $path = $this->endpoint->getPath();
+
+ //Accounts for trailing '/' in path when custom endpoint
+ //is provided to endpointProviderV2
+ if ($this->api->isModifiedModel()
+ && $this->api->getServiceName() === 's3'
+ ) {
+ if (substr($path, -1) === '/' && $relative[0] === '/') {
+ $path = rtrim($path, '/');
+ }
+ $relative = $path . $relative;
+ }
+ // If endpoint has path, remove leading '/' to preserve URI resolution.
+ if ($path && $relative[0] === '/') {
+ $relative = substr($relative, 1);
+ }
+
+ //Append path to endpoint when leading '//...' present
+ // as uri cannot be properly resolved
+ if ($this->api->isModifiedModel()
+ && strpos($relative, '//') === 0
+ ) {
+ return new Uri($this->endpoint . $relative);
+ }
+
+ // Expand path place holders using Amazon's slightly different URI
+ // template syntax.
+ return UriResolver::resolve($this->endpoint, new Uri($relative));
+ }
+
+ /**
+ * @param StructureShape $input
+ */
+ private function hasPayloadParam(StructureShape $input, $payload)
+ {
+ if ($payload) {
+ $potentiallyEmptyTypes = ['blob','string'];
+ if ($this->api->getMetadata('protocol') == 'rest-xml') {
+ $potentiallyEmptyTypes[] = 'structure';
+ }
+ $payloadMember = $input->getMember($payload);
+ if (in_array($payloadMember['type'], $potentiallyEmptyTypes)) {
+ return false;
+ }
+ }
+ foreach ($input->getMembers() as $member) {
+ if (!isset($member['location'])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function appendQuery($query, $endpoint)
+ {
+ $append = Psr7\Query::build($query);
+ return $endpoint .= strpos($endpoint, '?') !== false ? "&{$append}" : "?{$append}";
+ }
+
+ private function getVarDefinitions($command, $args)
+ {
+ $varDefinitions = [];
+
+ foreach ($command->getInput()->getMembers() as $name => $member) {
+ if ($member['location'] == 'uri') {
+ $varDefinitions[$member['locationName'] ?: $name] =
+ isset($args[$name])
+ ? $args[$name]
+ : null;
+ }
+ }
+ return $varDefinitions;
+ }
+}