PluginProbe
Media Cloud Sync / 1.2.13
Media Cloud Sync v1.2.13
1.4.2 1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 All 36 releases
media-cloud-sync / includes / sdk / s3 / Aws / Api / Serializer / RestSerializer.php

RestSerializer.php in Media Cloud Sync 1.2.13, at includes/sdk/s3/Aws/Api/Serializer/RestSerializer.php

240 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\Aws\Api\Serializer;
4
5 use Dudlewebs\WPMCS\s3\Aws\Api\MapShape;
6 use Dudlewebs\WPMCS\s3\Aws\Api\Service;
7 use Dudlewebs\WPMCS\s3\Aws\Api\Operation;
8 use Dudlewebs\WPMCS\s3\Aws\Api\Shape;
9 use Dudlewebs\WPMCS\s3\Aws\Api\StructureShape;
10 use Dudlewebs\WPMCS\s3\Aws\Api\TimestampShape;
11 use Dudlewebs\WPMCS\s3\Aws\CommandInterface;
12 use Dudlewebs\WPMCS\s3\Aws\EndpointV2\EndpointProviderV2;
13 use Dudlewebs\WPMCS\s3\Aws\EndpointV2\EndpointV2SerializerTrait;
14 use Dudlewebs\WPMCS\s3\Aws\EndpointV2\Ruleset\RulesetEndpoint;
15 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7;
16 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\Request;
17 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\Uri;
18 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\UriResolver;
19 use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface;
20 /**
21 * Serializes HTTP locations like header, uri, payload, etc...
22 * @internal
23 */
24 abstract class RestSerializer
25 {
26 use EndpointV2SerializerTrait;
27 /** @var Service */
28 private $api;
29 /** @var Uri */
30 private $endpoint;
31 /**
32 * @param Service $api Service API description
33 * @param string $endpoint Endpoint to connect to
34 */
35 public function __construct(Service $api, $endpoint)
36 {
37 $this->api = $api;
38 $this->endpoint = Psr7\Utils::uriFor($endpoint);
39 }
40 /**
41 * @param CommandInterface $command Command to serialize into a request.
42 * @param $endpointProvider Provider used for dynamic endpoint resolution.
43 * @param $clientArgs Client arguments used for dynamic endpoint resolution.
44 *
45 * @return RequestInterface
46 */
47 public function __invoke(CommandInterface $command, $endpoint = null)
48 {
49 $operation = $this->api->getOperation($command->getName());
50 $commandArgs = $command->toArray();
51 $opts = $this->serialize($operation, $commandArgs);
52 $headers = isset($opts['headers']) ? $opts['headers'] : [];
53 if ($endpoint instanceof RulesetEndpoint) {
54 $this->setEndpointV2RequestOptions($endpoint, $headers);
55 }
56 $uri = $this->buildEndpoint($operation, $commandArgs, $opts);
57 return new Request($operation['http']['method'], $uri, $headers, isset($opts['body']) ? $opts['body'] : null);
58 }
59 /**
60 * Modifies a hash of request options for a payload body.
61 *
62 * @param StructureShape $member Member to serialize
63 * @param array $value Value to serialize
64 * @param array $opts Request options to modify.
65 */
66 protected abstract function payload(StructureShape $member, array $value, array &$opts);
67 private function serialize(Operation $operation, array $args)
68 {
69 $opts = [];
70 $input = $operation->getInput();
71 // Apply the payload trait if present
72 if ($payload = $input['payload']) {
73 $this->applyPayload($input, $payload, $args, $opts);
74 }
75 foreach ($args as $name => $value) {
76 if ($input->hasMember($name)) {
77 $member = $input->getMember($name);
78 $location = $member['location'];
79 if (!$payload && !$location) {
80 $bodyMembers[$name] = $value;
81 } elseif ($location == 'header') {
82 $this->applyHeader($name, $member, $value, $opts);
83 } elseif ($location == 'querystring') {
84 $this->applyQuery($name, $member, $value, $opts);
85 } elseif ($location == 'headers') {
86 $this->applyHeaderMap($name, $member, $value, $opts);
87 }
88 }
89 }
90 if (isset($bodyMembers)) {
91 $this->payload($operation->getInput(), $bodyMembers, $opts);
92 } else {
93 if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) {
94 $this->payload($operation->getInput(), [], $opts);
95 }
96 }
97 return $opts;
98 }
99 private function applyPayload(StructureShape $input, $name, array $args, array &$opts)
100 {
101 if (!isset($args[$name])) {
102 return;
103 }
104 $m = $input->getMember($name);
105 if ($m['streaming'] || ($m['type'] == 'string' || $m['type'] == 'blob')) {
106 // Streaming bodies or payloads that are strings are
107 // always just a stream of data.
108 $opts['body'] = Psr7\Utils::streamFor($args[$name]);
109 return;
110 }
111 $this->payload($m, $args[$name], $opts);
112 }
113 private function applyHeader($name, Shape $member, $value, array &$opts)
114 {
115 if ($member->getType() === 'timestamp') {
116 $timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'rfc822';
117 $value = TimestampShape::format($value, $timestampFormat);
118 } elseif ($member->getType() === 'boolean') {
119 $value = $value ? 'true' : 'false';
120 }
121 if ($member['jsonvalue']) {
122 $value = \json_encode($value);
123 if (empty($value) && \JSON_ERROR_NONE !== \json_last_error()) {
124 throw new \InvalidArgumentException('Unable to encode the provided value' . ' with \'json_encode\'. ' . \json_last_error_msg());
125 }
126 $value = \base64_encode($value);
127 }
128 $opts['headers'][$member['locationName'] ?: $name] = $value;
129 }
130 /**
131 * Note: This is currently only present in the Amazon S3 model.
132 */
133 private function applyHeaderMap($name, Shape $member, array $value, array &$opts)
134 {
135 $prefix = $member['locationName'];
136 foreach ($value as $k => $v) {
137 $opts['headers'][$prefix . $k] = $v;
138 }
139 }
140 private function applyQuery($name, Shape $member, $value, array &$opts)
141 {
142 if ($member instanceof MapShape) {
143 $opts['query'] = isset($opts['query']) && \is_array($opts['query']) ? $opts['query'] + $value : $value;
144 } elseif ($value !== null) {
145 $type = $member->getType();
146 if ($type === 'boolean') {
147 $value = $value ? 'true' : 'false';
148 } elseif ($type === 'timestamp') {
149 $timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'iso8601';
150 $value = TimestampShape::format($value, $timestampFormat);
151 }
152 $opts['query'][$member['locationName'] ?: $name] = $value;
153 }
154 }
155 private function buildEndpoint(Operation $operation, array $args, array $opts)
156 {
157 // Create an associative array of variable definitions used in expansions
158 $varDefinitions = $this->getVarDefinitions($operation, $args);
159 $relative = \preg_replace_callback('/\\{([^\\}]+)\\}/', function (array $matches) use($varDefinitions) {
160 $isGreedy = \substr($matches[1], -1, 1) == '+';
161 $k = $isGreedy ? \substr($matches[1], 0, -1) : $matches[1];
162 if (!isset($varDefinitions[$k])) {
163 return '';
164 }
165 if ($isGreedy) {
166 return \str_replace('%2F', '/', \rawurlencode($varDefinitions[$k]));
167 }
168 return \rawurlencode($varDefinitions[$k]);
169 }, $operation['http']['requestUri']);
170 // Add the query string variables or appending to one if needed.
171 if (!empty($opts['query'])) {
172 $relative = $this->appendQuery($opts['query'], $relative);
173 }
174 $path = $this->endpoint->getPath();
175 //Accounts for trailing '/' in path when custom endpoint
176 //is provided to endpointProviderV2
177 if ($this->api->isModifiedModel() && $this->api->getServiceName() === 's3') {
178 if (\substr($path, -1) === '/' && $relative[0] === '/') {
179 $path = \rtrim($path, '/');
180 }
181 $relative = $path . $relative;
182 if (\strpos($relative, '../') !== \false || \substr($relative, -2) === '..') {
183 if ($relative[0] !== '/') {
184 $relative = '/' . $relative;
185 }
186 return new Uri($this->endpoint->withPath('') . $relative);
187 }
188 }
189 // If endpoint has path, remove leading '/' to preserve URI resolution.
190 if ($path && $relative[0] === '/') {
191 $relative = \substr($relative, 1);
192 }
193 //Append path to endpoint when leading '//...'
194 // present as uri cannot be properly resolved
195 if ($this->api->isModifiedModel() && \strpos($relative, '//') === 0) {
196 return new Uri($this->endpoint . $relative);
197 }
198 // Expand path place holders using Amazon's slightly different URI
199 // template syntax.
200 return UriResolver::resolve($this->endpoint, new Uri($relative));
201 }
202 /**
203 * @param StructureShape $input
204 */
205 private function hasPayloadParam(StructureShape $input, $payload)
206 {
207 if ($payload) {
208 $potentiallyEmptyTypes = ['blob', 'string'];
209 if ($this->api->getMetadata('protocol') == 'rest-xml') {
210 $potentiallyEmptyTypes[] = 'structure';
211 }
212 $payloadMember = $input->getMember($payload);
213 if (\in_array($payloadMember['type'], $potentiallyEmptyTypes)) {
214 return \false;
215 }
216 }
217 foreach ($input->getMembers() as $member) {
218 if (!isset($member['location'])) {
219 return \true;
220 }
221 }
222 return \false;
223 }
224 private function appendQuery($query, $endpoint)
225 {
226 $append = Psr7\Query::build($query);
227 return $endpoint .= \strpos($endpoint, '?') !== \false ? "&{$append}" : "?{$append}";
228 }
229 private function getVarDefinitions($command, $args)
230 {
231 $varDefinitions = [];
232 foreach ($command->getInput()->getMembers() as $name => $member) {
233 if ($member['location'] == 'uri') {
234 $varDefinitions[$member['locationName'] ?: $name] = isset($args[$name]) ? $args[$name] : null;
235 }
236 }
237 return $varDefinitions;
238 }
239 }
240