Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace Aws;
4
 
5
use Aws\Credentials\CredentialsInterface;
6
use Aws\Credentials\CredentialSources;
7
 
8
/**
9
 * A placeholder for gathering metrics in a request.
10
 *
11
 * @internal
12
 */
13
final class MetricsBuilder
14
{
15
    const WAITER = "B";
16
    const PAGINATOR = "C";
17
    const RETRY_MODE_LEGACY = "D";
18
    const RETRY_MODE_STANDARD = "E";
19
    const RETRY_MODE_ADAPTIVE = "F";
20
    const S3_TRANSFER = "G";
21
    const S3_CRYPTO_V1N = "H";
22
    const S3_CRYPTO_V2 = "I";
23
    const S3_EXPRESS_BUCKET = "J";
24
    const GZIP_REQUEST_COMPRESSION = "L";
25
    const ENDPOINT_OVERRIDE = "N";
26
    const ACCOUNT_ID_ENDPOINT = "O";
27
    const ACCOUNT_ID_MODE_PREFERRED = "P";
28
    const ACCOUNT_ID_MODE_DISABLED = "Q";
29
    const ACCOUNT_ID_MODE_REQUIRED = "R";
30
    const SIGV4A_SIGNING = "S";
31
    const RESOLVED_ACCOUNT_ID = "T";
32
    const FLEXIBLE_CHECKSUMS_REQ_CRC32 = "U";
33
    const FLEXIBLE_CHECKSUMS_REQ_CRC32C = "V";
34
    const FLEXIBLE_CHECKSUMS_REQ_CRC64 = "W";
35
    const FLEXIBLE_CHECKSUMS_REQ_SHA1 = "X";
36
    const FLEXIBLE_CHECKSUMS_REQ_SHA256 = "Y";
37
    const FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED = "Z";
38
    const FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED = "a";
39
    const FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED = "b";
40
    const FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED = "c";
41
    const CREDENTIALS_CODE = "e";
42
    const CREDENTIALS_ENV_VARS = "g";
43
    const CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN = "h";
44
    const CREDENTIALS_STS_ASSUME_ROLE = "i";
45
    const CREDENTIALS_STS_ASSUME_ROLE_WEB_ID = "k";
46
    const CREDENTIALS_PROFILE = "n";
47
    const CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN = "q";
48
    const CREDENTIALS_HTTP = "z";
49
    const CREDENTIALS_IMDS = "0";
50
    const CREDENTIALS_PROFILE_PROCESS = "v";
51
    const CREDENTIALS_PROFILE_SSO = "r";
52
    const CREDENTIALS_PROFILE_SSO_LEGACY = "t";
53
 
54
    /** @var int */
55
    private static $MAX_METRICS_SIZE = 1024; // 1KB or 1024 B
56
 
57
    /** @var string */
58
    private static $METRIC_SEPARATOR = ",";
59
 
60
    /** @var array $metrics */
61
    private $metrics;
62
 
63
    /** @var int $metricsSize */
64
    private $metricsSize;
65
 
66
    public function __construct()
67
    {
68
        $this->metrics = [];
69
        // The first metrics does not include the separator
70
        // therefore it is reduced by default.
71
        $this->metricsSize = -(strlen(self::$METRIC_SEPARATOR));
72
    }
73
 
74
    /**
75
     * Build the metrics string value.
76
     *
77
     * @return string
78
     */
79
    public function build(): string
80
    {
81
        if (empty($this->metrics)) {
82
            return "";
83
        }
84
 
85
        return $this->encode();
86
    }
87
 
88
    /**
89
     * Encodes the metrics by separating each metric
90
     * with a comma. Example: for the metrics[A,B,C] then
91
     * the output would be "A,B,C".
92
     *
93
     * @return string
94
     */
95
    private function encode(): string
96
    {
97
        return implode(self::$METRIC_SEPARATOR, array_keys($this->metrics));
98
    }
99
 
100
    /**
101
     * Appends a metric to the internal metrics holder after validating it.
102
     * Increases the current metrics size by the length of the new metric
103
     * plus the length of the encoding separator.
104
     * Example: $currentSize = $currentSize + len($newMetric) + len($separator)
105
     *
106
     * @param string $metric The metric to append.
107
     *
108
     * @return void
109
     */
110
    public function append(string $metric): void
111
    {
112
        if (!$this->canMetricBeAppended($metric)) {
113
            return;
114
        }
115
 
116
        $this->metrics[$metric] = true;
117
        $this->metricsSize += strlen($metric) + strlen(self::$METRIC_SEPARATOR);
118
    }
119
 
120
    /**
121
     * Receives a feature group and a value to identify which one is the metric.
122
     * For example, a group could be `signature` and a value could be `v4a`,
123
     * then the metric will be `SIGV4A_SIGNING`.
124
     *
125
     * @param string $featureGroup the feature group such as `signature`.
126
     * @param mixed $value the value for identifying the metric.
127
     *
128
     * @return void
129
     */
130
    public function identifyMetricByValueAndAppend(
131
        string $featureGroup,
132
        $value
133
    ): void
134
    {
135
        if (empty($value)) {
136
            return;
137
        }
138
 
139
        static $appendMetricFns = [
140
            'signature' => 'appendSignatureMetric',
141
            'request_compression' => 'appendRequestCompressionMetric',
142
            'request_checksum' => 'appendRequestChecksumMetric',
143
            'credentials' => 'appendCredentialsMetric',
144
            'account_id_endpoint_mode' => 'appendAccountIdEndpointMode',
145
            'account_id_endpoint' => 'appendAccountIdEndpoint',
146
            'request_checksum_calculation' => 'appendRequestChecksumCalculationMetric',
147
        ];
148
 
149
        $fn = $appendMetricFns[$featureGroup];
150
        $this->{$fn}($value);
151
    }
152
 
153
    /**
154
     * Appends the signature metric based on the signature value.
155
     *
156
     * @param string $signature
157
     *
158
     * @return void
159
     */
160
    private function appendSignatureMetric(string $signature): void
161
    {
162
        if ($signature === 'v4-s3express') {
163
            $this->append(self::S3_EXPRESS_BUCKET);
164
        } elseif ($signature === 'v4a') {
165
            $this->append(self::SIGV4A_SIGNING);
166
        }
167
    }
168
 
169
    /**
170
     * Appends the request compression metric based on the format resolved.
171
     *
172
     * @param string $format
173
     *
174
     * @return void
175
     */
176
    private function appendRequestCompressionMetric(string $format): void
177
    {
178
        if ($format === 'gzip') {
179
            $this->append(self::GZIP_REQUEST_COMPRESSION);
180
        }
181
    }
182
 
183
    /**
184
     * Appends the request checksum metric based on the algorithm.
185
     *
186
     * @param string $algorithm
187
     *
188
     * @return void
189
     */
190
    private function appendRequestChecksumMetric(string $algorithm): void
191
    {
192
        if ($algorithm === 'crc32') {
193
            $this->append(self::FLEXIBLE_CHECKSUMS_REQ_CRC32);
194
        } elseif ($algorithm === 'crc32c') {
195
            $this->append(self::FLEXIBLE_CHECKSUMS_REQ_CRC32C);
196
        } elseif ($algorithm === 'crc64') {
197
            $this->append(self::FLEXIBLE_CHECKSUMS_REQ_CRC64);
198
        } elseif ($algorithm === 'sha1') {
199
            $this->append(self::FLEXIBLE_CHECKSUMS_REQ_SHA1);
200
        } elseif ($algorithm === 'sha256') {
201
            $this->append(self::FLEXIBLE_CHECKSUMS_REQ_SHA256);
202
        }
203
    }
204
 
205
 
206
    /**
207
     * Appends the credentials metric based on the type of credentials
208
     * resolved.
209
     *
210
     * @param CredentialsInterface $credentials
211
     *
212
     * @return void
213
     */
214
    private function appendCredentialsMetric(
215
        CredentialsInterface $credentials
216
    ): void
217
    {
218
        $source = $credentials->toArray()['source'] ?? null;
219
        if (empty($source)) {
220
            return;
221
        }
222
 
223
        static $credentialsMetricMapping = [
224
            CredentialSources::STATIC =>
225
                self::CREDENTIALS_CODE,
226
            CredentialSources::ENVIRONMENT =>
227
                self::CREDENTIALS_ENV_VARS,
228
            CredentialSources::ENVIRONMENT_STS_WEB_ID_TOKEN =>
229
                self::CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN,
230
            CredentialSources::STS_ASSUME_ROLE =>
231
                self::CREDENTIALS_STS_ASSUME_ROLE,
232
            CredentialSources::STS_WEB_ID_TOKEN =>
233
                self::CREDENTIALS_STS_ASSUME_ROLE_WEB_ID,
234
            CredentialSources::PROFILE =>
235
                self::CREDENTIALS_PROFILE,
236
            CredentialSources::IMDS =>
237
                self::CREDENTIALS_IMDS,
238
            CredentialSources::ECS =>
239
                self::CREDENTIALS_HTTP,
240
            CredentialSources::PROFILE_STS_WEB_ID_TOKEN =>
241
                self::CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN,
242
            CredentialSources::PROFILE_PROCESS =>
243
                self::CREDENTIALS_PROFILE_PROCESS,
244
            CredentialSources::PROFILE_SSO =>
245
                self::CREDENTIALS_PROFILE_SSO,
246
            CredentialSources::PROFILE_SSO_LEGACY =>
247
                self::CREDENTIALS_PROFILE_SSO_LEGACY,
248
        ];
249
        if (isset($credentialsMetricMapping[$source])) {
250
            $this->append($credentialsMetricMapping[$source]);
251
        }
252
    }
253
 
254
    private function appendRequestChecksumCalculationMetric(
255
        string $checkSumCalculation
256
    ): void
257
    {
258
        static $checksumCalculationMetricMapping = [
259
            'when_supported' => self::FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED,
260
            'when_required' => self::FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED,
261
        ];
262
 
263
        if (isset($checksumCalculationMetricMapping[$checkSumCalculation])) {
264
            $this->append($checksumCalculationMetricMapping[$checkSumCalculation]);
265
        }
266
    }
267
 
268
    /**
269
     * Appends the account_id_endpoint_mode metrics based on
270
     * the value resolved.
271
     *
272
     * @param string $accountIdEndpointMode
273
     *
274
     * @return void
275
     */
276
    private function appendAccountIdEndpointMode(
277
        string $accountIdEndpointMode
278
    ): void
279
    {
280
        if (empty($accountIdEndpointMode)) {
281
            return;
282
        }
283
 
284
        if ($accountIdEndpointMode === 'preferred') {
285
            $this->append(self::ACCOUNT_ID_MODE_PREFERRED);
286
        } elseif ($accountIdEndpointMode === 'disabled') {
287
            $this->append(self::ACCOUNT_ID_MODE_DISABLED);
288
        } elseif ($accountIdEndpointMode === 'required') {
289
            $this->append(self::ACCOUNT_ID_MODE_REQUIRED);
290
        }
291
    }
292
 
293
    /**
294
     * Appends the account_id_endpoint metric whenever a resolved endpoint
295
     * matches an account_id endpoint pattern which also defined here.
296
     *
297
     * @param string $endpoint
298
     *
299
     * @return void
300
     */
301
    private function appendAccountIdEndpoint(string $endpoint): void
302
    {
303
        static $pattern = "/(https|http):\\/\\/\\d{12}\\.ddb/";
304
        if (preg_match($pattern, $endpoint)) {
305
            $this->append(self::ACCOUNT_ID_ENDPOINT);
306
        }
307
    }
308
 
309
    /**
310
     * Resolves metrics from client arguments.
311
     *
312
     * @param array $args
313
     *
314
     * @return void
315
     */
316
    public function resolveAndAppendFromArgs(array $args = []): void
317
    {
318
        static $metricsFnList = [
319
            'appendEndpointMetric',
320
            'appendRetryConfigMetric',
321
            'appendResponseChecksumValidationMetric',
322
        ];
323
        foreach ($metricsFnList as $metricFn) {
324
            $this->{$metricFn}($args);
325
        }
326
    }
327
 
328
    /**
329
     * Appends the endpoint metric into the metrics builder,
330
     * just if a custom endpoint was provided at client construction.
331
     *
332
     * @param array $args
333
     *
334
     * @return void
335
     */
336
    private function appendEndpointMetric(array $args): void
337
    {
338
        if (!empty($args['endpoint_override'])) {
339
            $this->append(MetricsBuilder::ENDPOINT_OVERRIDE);
340
        }
341
    }
342
 
343
    /**
344
     * Appends the retry mode metric into the metrics builder,
345
     * based on the resolved retry config mode.
346
     *
347
     * @param array $args
348
     *
349
     * @return void
350
     */
351
    private function appendRetryConfigMetric(array $args): void
352
    {
353
        $retries = $args['retries'] ?? null;
354
        if ($retries === null) {
355
            return;
356
        }
357
 
358
        $retryMode = '';
359
        if ($retries instanceof \Aws\Retry\Configuration) {
360
            $retryMode = $retries->getMode();
361
        } elseif (is_array($retries)
362
            && isset($retries["mode"])
363
        ) {
364
            $retryMode = $retries["mode"];
365
        }
366
 
367
        if ($retryMode === 'legacy') {
368
            $this->append(
369
                MetricsBuilder::RETRY_MODE_LEGACY
370
            );
371
        } elseif ($retryMode === 'standard') {
372
            $this->append(
373
                MetricsBuilder::RETRY_MODE_STANDARD
374
            );
375
        } elseif ($retryMode === 'adaptive') {
376
            $this->append(
377
                MetricsBuilder::RETRY_MODE_ADAPTIVE
378
            );
379
        }
380
    }
381
 
382
    /**
383
     * Appends the provided/resolved response checksum validation mode.
384
     *
385
     * @param array $args
386
     *
387
     * @return void
388
     */
389
    private function appendResponseChecksumValidationMetric(array $args): void
390
    {
391
        if (empty($args['response_checksum_validation'])) {
392
            return;
393
        }
394
 
395
        $checksumValidation = $args['response_checksum_validation'];
396
        static $checksumValidationMetricMapping = [
397
            'when_supported' => MetricsBuilder::FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED,
398
            'when_required' => MetricsBuilder::FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED,
399
        ];
400
 
401
        if (isset($checksumValidationMetricMapping[$checksumValidation])) {
402
            $this->append($checksumValidationMetricMapping[$checksumValidation]);
403
        }
404
    }
405
 
406
    /**
407
     * Validates if a metric can be appended by ensuring the total size,
408
     * including the new metric and separator, does not exceed the limit.
409
     * Also checks that the metric does not already exist.
410
     * Example: Appendable if:
411
     *  $currentSize + len($newMetric) + len($separator) <= MAX_SIZE
412
     *  and:
413
     * $newMetric not in $existingMetrics
414
     *
415
     * @param string $newMetric The metric to validate.
416
     *
417
     * @return bool True if the metric can be appended, false otherwise.
418
     */
419
    private function canMetricBeAppended(string $newMetric): bool
420
    {
421
        if ($newMetric === "") {
422
            return false;
423
        }
424
 
425
        if ($this->metricsSize
426
            + (strlen($newMetric) + strlen(self::$METRIC_SEPARATOR))
427
            > self::$MAX_METRICS_SIZE
428
        ) {
429
            return false;
430
        }
431
 
432
        if (isset($this->metrics[$newMetric])) {
433
            return false;
434
        }
435
 
436
        return true;
437
    }
438
 
439
    /**
440
     * Returns the metrics builder from the property @context of a command.
441
     *
442
     * @param Command $command
443
     *
444
     * @return MetricsBuilder
445
     */
446
    public static function fromCommand(CommandInterface $command): MetricsBuilder
447
    {
448
        return $command->getMetricsBuilder();
449
    }
450
 
451
    /**
452
     * Helper method for appending a metrics capture middleware into a
453
     * handler stack given. The middleware appended here is on top of the
454
     * build step.
455
     *
456
     * @param HandlerList $handlerList
457
     * @param $metric
458
     *
459
     * @return void
460
     */
461
    public static function appendMetricsCaptureMiddleware(
462
        HandlerList $handlerList,
463
        $metric
464
    ): void
465
    {
466
        $middlewareName = 'metrics-capture-'.$metric;
467
        if (!$handlerList->hasMiddleware($middlewareName)) {
468
            $handlerList->appendBuild(
469
                Middleware::tap(
470
                    function (CommandInterface $command) use ($metric) {
471
                        self::fromCommand($command)->append(
472
                            $metric
473
                        );
474
                    }
475
                ),
476
                $middlewareName
477
            );
478
        }
479
    }
480
}