PluginProbe
Media Cloud Sync / 1.3.11
Media Cloud Sync v1.3.11
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 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / s3 / Aws / S3 / ApplyChecksumMiddleware.php

ApplyChecksumMiddleware.php in Media Cloud Sync 1.3.11, at includes/sdk/s3/Aws/S3/ApplyChecksumMiddleware.php

163 lines 6.4 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\S3;
4
5 use Dudlewebs\WPMCS\s3\Aws\Api\Service;
6 use Dudlewebs\WPMCS\s3\Aws\Api\Shape;
7 use Dudlewebs\WPMCS\s3\Aws\CommandInterface;
8 use Dudlewebs\WPMCS\s3\Aws\MetricsBuilder;
9 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7;
10 use InvalidArgumentException;
11 use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface;
12 use Dudlewebs\WPMCS\s3\Psr\Http\Message\StreamInterface;
13 /**
14 * Apply required or optional checksums to requests before sending.
15 *
16 * IMPORTANT: This middleware must be added after the "build" step.
17 *
18 * @internal
19 */
20 class ApplyChecksumMiddleware
21 {
22 use CalculatesChecksumTrait;
23 public const DEFAULT_CALCULATION_MODE = 'when_supported';
24 public const DEFAULT_ALGORITHM = 'crc32';
25 /**
26 * @var true[]
27 *
28 * S3 Operations for which pre-calculated SHA256
29 * Checksums can be added to the command
30 */
31 public static $sha256 = ['PutObject' => \true, 'UploadPart' => \true];
32 /** @var Service */
33 private $api;
34 /** @var array */
35 private $config;
36 /** @var callable */
37 private $nextHandler;
38 /**
39 * Create a middleware wrapper function.
40 *
41 * @param Service $api
42 * @return callable
43 */
44 public static function wrap(Service $api, array $config = [])
45 {
46 return function (callable $handler) use($api, $config) {
47 return new self($handler, $api, $config);
48 };
49 }
50 public function __construct(callable $nextHandler, Service $api, array $config = [])
51 {
52 $this->api = $api;
53 $this->nextHandler = $nextHandler;
54 $this->config = $config;
55 }
56 public function __invoke(CommandInterface $command, RequestInterface $request)
57 {
58 $next = $this->nextHandler;
59 $name = $command->getName();
60 $body = $request->getBody();
61 $operation = $this->api->getOperation($name);
62 $mode = $this->config['request_checksum_calculation'] ?? self::DEFAULT_CALCULATION_MODE;
63 $command->getMetricsBuilder()->identifyMetricByValueAndAppend('request_checksum_calculation', $mode);
64 // Trigger warning if AddContentMD5 is specified for PutObject or UploadPart
65 $this->handleDeprecatedAddContentMD5($command);
66 $checksumInfo = $operation['httpChecksum'] ?? [];
67 $checksumMemberName = $checksumInfo['requestAlgorithmMember'] ?? '';
68 $checksumMember = !empty($checksumMemberName) ? $operation->getInput()->getMember($checksumMemberName) : null;
69 $checksumRequired = $checksumInfo['requestChecksumRequired'] ?? \false;
70 $requestedAlgorithm = $command[$checksumMemberName] ?? null;
71 $shouldAddChecksum = $this->shouldAddChecksum($mode, $checksumRequired, $checksumMember, $requestedAlgorithm);
72 if ($shouldAddChecksum) {
73 if (!$this->hasAlgorithmHeader($request)) {
74 $supportedAlgorithms = \array_map('strtolower', $checksumMember['enum'] ?? []);
75 $algorithm = $this->determineChecksumAlgorithm($supportedAlgorithms, $requestedAlgorithm, $checksumMemberName);
76 $request = $this->addAlgorithmHeader($algorithm, $request, $body);
77 $command->getMetricsBuilder()->identifyMetricByValueAndAppend('request_checksum', $algorithm);
78 }
79 }
80 // Set the content hash header if ContentSHA256 is provided
81 if (isset(self::$sha256[$name]) && $command['ContentSHA256']) {
82 $request = $request->withHeader('X-Amz-Content-Sha256', $command['ContentSHA256']);
83 $command->getMetricsBuilder()->append(MetricsBuilder::FLEXIBLE_CHECKSUMS_REQ_SHA256);
84 }
85 return $next($command, $request);
86 }
87 /**
88 * @param CommandInterface $command
89 *
90 * @return void
91 */
92 private function handleDeprecatedAddContentMD5(CommandInterface $command) : void
93 {
94 if (!empty($command['AddContentMD5'])) {
95 \trigger_error('S3 no longer supports MD5 checksums. ' . 'A CRC32 checksum will be computed and applied on your behalf.', \E_USER_DEPRECATED);
96 $command['ChecksumAlgorithm'] = self::DEFAULT_ALGORITHM;
97 }
98 }
99 /**
100 * @param string $mode
101 * @param Shape|null $checksumMember
102 * @param string $name
103 * @param bool $checksumRequired
104 * @param string|null $requestedAlgorithm
105 *
106 * @return bool
107 */
108 private function shouldAddChecksum(string $mode, bool $checksumRequired, ?Shape $checksumMember, ?string $requestedAlgorithm) : bool
109 {
110 return $mode === 'when_supported' && $checksumMember || $mode === 'when_required' && ($checksumRequired || $checksumMember && $requestedAlgorithm);
111 }
112 /**
113 * @param Shape|null $checksumMember
114 * @param string|null $requestedAlgorithm
115 * @param string|null $checksumMemberName
116 *
117 * @return string
118 */
119 private function determineChecksumAlgorithm(array $supportedAlgorithms, ?string $requestedAlgorithm, ?string $checksumMemberName) : string
120 {
121 $algorithm = self::DEFAULT_ALGORITHM;
122 if ($requestedAlgorithm) {
123 $requestedAlgorithm = \strtolower($requestedAlgorithm);
124 if (!\in_array($requestedAlgorithm, $supportedAlgorithms)) {
125 throw new InvalidArgumentException("Unsupported algorithm supplied for input variable {$checksumMemberName}. " . "Supported checksums for this operation include: " . \implode(", ", $supportedAlgorithms) . ".");
126 }
127 $algorithm = $requestedAlgorithm;
128 }
129 return $algorithm;
130 }
131 /**
132 * @param string $requestedAlgorithm
133 * @param RequestInterface $request
134 * @param StreamInterface $body
135 *
136 * @return RequestInterface
137 */
138 private function addAlgorithmHeader(string $requestedAlgorithm, RequestInterface $request, StreamInterface $body) : RequestInterface
139 {
140 $headerName = "x-amz-checksum-{$requestedAlgorithm}";
141 if (!$request->hasHeader($headerName)) {
142 $encoded = self::getEncodedValue($requestedAlgorithm, $body);
143 $request = $request->withHeader($headerName, $encoded);
144 }
145 return $request;
146 }
147 /**
148 * @param RequestInterface $request
149 *
150 * @return bool
151 */
152 private function hasAlgorithmHeader(RequestInterface $request) : bool
153 {
154 $headers = $request->getHeaders();
155 foreach ($headers as $name => $values) {
156 if (\stripos($name, 'x-amz-checksum-') === 0) {
157 return \true;
158 }
159 }
160 return \false;
161 }
162 }
163