Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\S3;
3
 
4
use Aws\Arn\ArnParser;
5
use Aws\Arn\ObjectLambdaAccessPointArn;
6
use Aws\ClientResolver;
7
use Aws\CommandInterface;
8
use Aws\Endpoint\EndpointProvider;
9
use Aws\Endpoint\PartitionEndpointProvider;
10
use GuzzleHttp\Exception\InvalidArgumentException;
11
use GuzzleHttp\Psr7\Uri;
12
use Psr\Http\Message\RequestInterface;
13
 
14
/**
15
 * Used to update the URL used for S3 requests to support:
16
 * S3 Accelerate, S3 DualStack or Both. It will build to
17
 * host style paths unless specified, including for S3
18
 * DualStack.
19
 *
20
 * IMPORTANT: this middleware must be added after the "build" step.
21
 *
22
 * @internal
23
 */
24
class S3EndpointMiddleware
25
{
26
    private static $exclusions = [
27
        'CreateBucket' => true,
28
        'DeleteBucket' => true,
29
        'ListBuckets' => true,
30
    ];
31
 
32
    const NO_PATTERN = 0;
33
    const DUALSTACK = 1;
34
    const ACCELERATE = 2;
35
    const ACCELERATE_DUALSTACK = 3;
36
    const PATH_STYLE = 4;
37
    const HOST_STYLE = 5;
38
 
39
    /** @var bool */
40
    private $accelerateByDefault;
41
    /** @var bool */
42
    private $dualStackByDefault;
43
    /** @var bool */
44
    private $pathStyleByDefault;
45
    /** @var string */
46
    private $region;
47
    /** @var callable */
48
    private $endpointProvider;
49
    /** @var callable */
50
    private $nextHandler;
51
    /** @var string */
52
    private $endpoint;
53
 
54
    /**
55
     * Create a middleware wrapper function
56
     *
57
     * @param string $region
58
     * @param EndpointProvider $endpointProvider
59
     * @param array  $options
60
     *
61
     * @return callable
62
     */
63
    public static function wrap($region, $endpointProvider, array $options)
64
    {
65
        return function (callable $handler) use ($region, $endpointProvider, $options) {
66
            return new self($handler, $region, $options, $endpointProvider);
67
        };
68
    }
69
 
70
    public function __construct(
71
        callable $nextHandler,
72
        $region,
73
        array $options,
74
        $endpointProvider = null
75
    ) {
76
        $this->pathStyleByDefault = isset($options['path_style'])
77
            ? (bool) $options['path_style'] : false;
78
        $this->dualStackByDefault = isset($options['dual_stack'])
79
            ? (bool) $options['dual_stack'] : false;
80
        $this->accelerateByDefault = isset($options['accelerate'])
81
            ? (bool) $options['accelerate'] : false;
82
        $this->region = (string) $region;
83
        $this->endpoint = isset($options['endpoint'])
84
            ? $options['endpoint'] : "";
85
        $this->endpointProvider = is_null($endpointProvider)
86
            ? PartitionEndpointProvider::defaultProvider()
87
            : $endpointProvider;
88
        $this->nextHandler = $nextHandler;
89
    }
90
 
91
    public function __invoke(CommandInterface $command, RequestInterface $request)
92
    {
93
        if (!empty($this->endpoint)) {
94
            $request = $this->applyEndpoint($command, $request);
95
        } else {
96
            switch ($this->endpointPatternDecider($command, $request)) {
97
                case self::HOST_STYLE:
98
                    $request = $this->applyHostStyleEndpoint($command, $request);
99
                    break;
100
                case self::NO_PATTERN:
101
                    break;
102
                case self::PATH_STYLE:
103
                    $request = $this->applyPathStyleEndpointCustomizations($command, $request);
104
                    break;
105
                case self::DUALSTACK:
106
                    $request = $this->applyDualStackEndpoint($command, $request);
107
                    break;
108
                case self::ACCELERATE:
109
                    $request = $this->applyAccelerateEndpoint(
110
                        $command,
111
                        $request,
112
                        's3-accelerate'
113
                    );
114
                    break;
115
                case self::ACCELERATE_DUALSTACK:
116
                    $request = $this->applyAccelerateEndpoint(
117
                        $command,
118
                        $request,
119
                        's3-accelerate.dualstack'
120
                    );
121
                    break;
122
            }
123
        }
124
        $nextHandler = $this->nextHandler;
125
        return $nextHandler($command, $request);
126
    }
127
 
128
    private static function isRequestHostStyleCompatible(
129
        CommandInterface $command,
130
        RequestInterface $request
131
    ) {
132
        return S3Client::isBucketDnsCompatible($command['Bucket'])
133
            && (
134
                $request->getUri()->getScheme() === 'http'
135
                || strpos($command['Bucket'], '.') === false
136
            )
137
            && filter_var($request->getUri()->getHost(), FILTER_VALIDATE_IP) === false;
138
    }
139
 
140
    private function endpointPatternDecider(
141
        CommandInterface $command,
142
        RequestInterface $request
143
    ) {
144
        $accelerate = isset($command['@use_accelerate_endpoint'])
145
            ? $command['@use_accelerate_endpoint'] : $this->accelerateByDefault;
146
        $dualStack = isset($command['@use_dual_stack_endpoint'])
147
            ? $command['@use_dual_stack_endpoint'] : $this->dualStackByDefault;
148
        $pathStyle = isset($command['@use_path_style_endpoint'])
149
            ? $command['@use_path_style_endpoint'] : $this->pathStyleByDefault;
150
 
151
        if ($accelerate && $dualStack) {
152
            // When try to enable both for operations excluded from s3-accelerate,
153
            // only dualstack endpoints will be enabled.
154
            return $this->canAccelerate($command)
155
                ? self::ACCELERATE_DUALSTACK
156
                : self::DUALSTACK;
157
        }
158
 
159
        if ($accelerate && $this->canAccelerate($command)) {
160
            return self::ACCELERATE;
161
        }
162
 
163
        if ($dualStack) {
164
            return self::DUALSTACK;
165
        }
166
 
167
        if (!$pathStyle
168
            && self::isRequestHostStyleCompatible($command, $request)
169
        ) {
170
            return self::HOST_STYLE;
171
        }
172
 
173
        return self::PATH_STYLE;
174
    }
175
 
176
    private function canAccelerate(CommandInterface $command)
177
    {
178
        return empty(self::$exclusions[$command->getName()])
179
            && S3Client::isBucketDnsCompatible($command['Bucket']);
180
    }
181
 
182
    private function getBucketStyleHost(CommandInterface $command, $host)
183
    {
184
        // For operations on the base host (e.g. ListBuckets)
185
        if (!isset($command['Bucket'])) {
186
            return $host;
187
        }
188
 
189
        return "{$command['Bucket']}.{$host}";
190
    }
191
 
192
    private function applyHostStyleEndpoint(
193
        CommandInterface $command,
194
        RequestInterface $request
195
    ) {
196
        $uri = $request->getUri();
197
        $request = $request->withUri(
198
            $uri->withHost($this->getBucketStyleHost(
199
                    $command,
200
                    $uri->getHost()
201
                ))
202
                ->withPath($this->getBucketlessPath(
203
                    $uri->getPath(),
204
                    $command
205
                ))
206
        );
207
        return $request;
208
    }
209
 
210
    private function applyPathStyleEndpointCustomizations(
211
        CommandInterface $command,
212
        RequestInterface $request
213
    ) {
214
        if ($command->getName() == 'WriteGetObjectResponse') {
215
            $dnsSuffix = $this->endpointProvider
216
                ->getPartition($this->region, 's3')
217
                ->getDnsSuffix();
218
            $fips = \Aws\is_fips_pseudo_region($this->region) ? "-fips" : "";
219
            $region = \Aws\strip_fips_pseudo_regions($this->region);
220
            $host =
221
                "{$command['RequestRoute']}.s3-object-lambda{$fips}.{$region}.{$dnsSuffix}";
222
 
223
            $uri = $request->getUri();
224
            $request = $request->withUri(
225
                $uri->withHost($host)
226
                    ->withPath($this->getBucketlessPath(
227
                        $uri->getPath(),
228
                        $command
229
                    ))
230
            );
231
        }
232
        return $request;
233
    }
234
 
235
 
236
    private function applyDualStackEndpoint(
237
        CommandInterface $command,
238
        RequestInterface $request
239
    ) {
240
        $request = $request->withUri(
241
            $request->getUri()->withHost($this->getDualStackHost())
242
        );
243
 
244
        if (empty($command['@use_path_style_endpoint'])
245
            && !$this->pathStyleByDefault
246
            && self::isRequestHostStyleCompatible($command, $request)
247
        ) {
248
            $request = $this->applyHostStyleEndpoint($command, $request);
249
        }
250
        return $request;
251
    }
252
 
253
    private function getDualStackHost()
254
    {
255
        $dnsSuffix = $this->endpointProvider
256
            ->getPartition($this->region, 's3')
257
            ->getDnsSuffix();
258
        return "s3.dualstack.{$this->region}.{$dnsSuffix}";
259
    }
260
 
261
    private function applyAccelerateEndpoint(
262
        CommandInterface $command,
263
        RequestInterface $request,
264
        $pattern
265
    ) {
266
        $request = $request->withUri(
267
            $request->getUri()
268
                ->withHost($this->getAccelerateHost($command, $pattern))
269
                ->withPath($this->getBucketlessPath(
270
                    $request->getUri()->getPath(),
271
                    $command
272
                ))
273
        );
274
        return $request;
275
    }
276
 
277
    private function getAccelerateHost(CommandInterface $command, $pattern)
278
    {
279
        $dnsSuffix = $this->endpointProvider
280
            ->getPartition($this->region, 's3')
281
            ->getDnsSuffix();
282
        return "{$command['Bucket']}.{$pattern}.{$dnsSuffix}";
283
    }
284
 
285
    private function getBucketlessPath($path, CommandInterface $command)
286
    {
287
        $pattern = '/^\\/' . preg_quote($command['Bucket'], '/') . '/';
288
        $path = preg_replace($pattern, '', $path) ?: '/';
289
        if (substr($path, 0 , 1) !== '/') {
290
            $path = '/' . $path;
291
        }
292
        return $path;
293
    }
294
 
295
    private function applyEndpoint(
296
        CommandInterface $command,
297
        RequestInterface $request
298
    ) {
299
        $dualStack = isset($command['@use_dual_stack_endpoint'])
300
            ? $command['@use_dual_stack_endpoint'] : $this->dualStackByDefault;
301
        if (ArnParser::isArn($command['Bucket'])) {
302
            $arn = ArnParser::parse($command['Bucket']);
303
            $outpost = $arn->getService() == 's3-outposts';
304
            if ($outpost && $dualStack) {
305
                throw new InvalidArgumentException("Outposts + dualstack is not supported");
306
            }
307
            if ($arn instanceof ObjectLambdaAccessPointArn) {
308
                return $request;
309
            }
310
        }
311
        if ($dualStack) {
312
            throw new InvalidArgumentException("Custom Endpoint + Dualstack not supported");
313
        }
314
        if ($command->getName() == 'WriteGetObjectResponse') {
315
            $host = "{$command['RequestRoute']}.{$this->endpoint}";
316
            $uri = $request->getUri();
317
            return $request = $request->withUri(
318
                $uri->withHost($host)
319
                    ->withPath($this->getBucketlessPath(
320
                        $uri->getPath(),
321
                        $command
322
                    ))
323
            );
324
        }
325
        $host = ($this->pathStyleByDefault) ?
326
            $this->endpoint :
327
            $this->getBucketStyleHost(
328
                $command,
329
                $this->endpoint
330
            );
331
        $uri = $request->getUri();
332
        $scheme = $uri->getScheme();
333
        if(empty($scheme)){
334
            $request = $request->withUri(
335
                $uri->withHost($host)
336
            );
337
        } else {
338
            $request = $request->withUri($uri);
339
        }
340
 
341
        return $request;
342
    }
343
}