Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws;
3
 
4
use Aws\Api\Service;
5
use Psr\Http\Message\RequestInterface;
6
 
7
/**
8
 * @internal Middleware that auto fills parameters with `idempotencyToken` trait
9
 */
10
class IdempotencyTokenMiddleware
11
{
12
    /** @var Service */
13
    private $service;
14
    /** @var string */
15
    private $bytesGenerator;
16
    /** @var callable */
17
    private $nextHandler;
18
 
19
    /**
20
     * Creates a middleware that populates operation parameter
21
     * with trait 'idempotencyToken' enabled with a random UUIDv4
22
     *
23
     * One of following functions needs to be available
24
     * in order to generate random bytes used for UUID
25
     * (SDK will attempt to utilize function in following order):
26
     *  - random_bytes (requires PHP 7.0 or above)
27
     *  - openssl_random_pseudo_bytes (requires 'openssl' module enabled)
28
     *  - mcrypt_create_iv (requires 'mcrypt' module enabled)
29
     *
30
     * You may also supply a custom bytes generator as an optional second
31
     * parameter.
32
     *
33
     * @param \Aws\Api\Service $service
34
     * @param callable|null $bytesGenerator
35
     *
36
     * @return callable
37
     */
38
    public static function wrap(
39
        Service $service,
40
        callable $bytesGenerator = null
41
    ) {
42
        return function (callable $handler) use ($service, $bytesGenerator) {
43
            return new self($handler, $service, $bytesGenerator);
44
        };
45
    }
46
 
47
    public function __construct(
48
        callable $nextHandler,
49
        Service $service,
50
        callable $bytesGenerator = null
51
    ) {
52
        $this->bytesGenerator = $bytesGenerator
53
            ?: $this->findCompatibleRandomSource();
54
        $this->service = $service;
55
        $this->nextHandler = $nextHandler;
56
    }
57
 
58
    public function __invoke(
59
        CommandInterface $command,
60
        RequestInterface $request = null
61
    ) {
62
        $handler = $this->nextHandler;
63
        if ($this->bytesGenerator) {
64
            $operation = $this->service->getOperation($command->getName());
65
            $members = $operation->getInput()->getMembers();
66
            foreach ($members as $member => $value) {
67
                if ($value['idempotencyToken']) {
68
                    $bytes = call_user_func($this->bytesGenerator, 16);
69
                    // populating UUIDv4 only when the parameter is not set
70
                    $command[$member] = $command[$member]
71
                        ?: $this->getUuidV4($bytes);
72
                    // only one member could have the trait enabled
73
                    break;
74
                }
75
            }
76
        }
77
        return $handler($command, $request);
78
    }
79
 
80
    /**
81
     * This function generates a random UUID v4 string,
82
     * which is used as auto filled token value.
83
     *
84
     * @param string $bytes 16 bytes of pseudo-random bytes
85
     * @return string
86
     * More information about UUID v4, see:
87
     * https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29
88
     * https://tools.ietf.org/html/rfc4122#page-14
89
     */
90
    private static function getUuidV4($bytes)
91
    {
92
        // set version to 0100
93
        $bytes[6] = chr(ord($bytes[6]) & 0x0f | 0x40);
94
        // set bits 6-7 to 10
95
        $bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80);
96
        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
97
    }
98
 
99
    /**
100
     * This function decides the PHP function used in generating random bytes.
101
     *
102
     * @return callable|null
103
     */
104
    private function findCompatibleRandomSource()
105
    {
106
        if (function_exists('random_bytes')) {
107
            return 'random_bytes';
108
        }
109
 
110
        if (function_exists('openssl_random_pseudo_bytes')) {
111
            return 'openssl_random_pseudo_bytes';
112
        }
113
 
114
        if (function_exists('mcrypt_create_iv')) {
115
            return 'mcrypt_create_iv';
116
        }
117
    }
118
}