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\Api\Parser\AbstractParser;
5
use Aws\Api\Service;
6
use Aws\Api\StructureShape;
7
use Aws\CommandInterface;
8
use Aws\S3\Exception\S3Exception;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\StreamInterface;
11
 
12
/**
13
 * @internal Decorates a parser for the S3 service to validate the response checksum.
14
 */
15
class ValidateResponseChecksumParser extends AbstractParser
16
{
17
    use CalculatesChecksumTrait;
18
    /**
19
     * @param callable $parser Parser to wrap.
20
     */
21
    public function __construct(callable $parser, Service $api)
22
    {
23
        $this->api = $api;
24
        $this->parser = $parser;
25
    }
26
 
27
    public function __invoke(
28
        CommandInterface $command,
29
        ResponseInterface $response
30
    ) {
31
        $fn = $this->parser;
32
        $result = $fn($command, $response);
33
 
34
        //Skip this middleware if the operation doesn't have an httpChecksum
35
        $op = $this->api->getOperation($command->getName());
36
        $checksumInfo = isset($op['httpChecksum'])
37
            ? $op['httpChecksum']
38
            : [];
39
        if (empty($checksumInfo)) {
40
            return $result;
41
        }
42
 
43
        //Skip this middleware if the operation doesn't send back a checksum, or the user doesn't opt in
44
        $checksumModeEnabledMember = isset($checksumInfo['requestValidationModeMember'])
45
            ? $checksumInfo['requestValidationModeMember']
46
            : "";
47
        $checksumModeEnabled = isset($command[$checksumModeEnabledMember])
48
            ? $command[$checksumModeEnabledMember]
49
            : "";
50
        $responseAlgorithms = isset($checksumInfo['responseAlgorithms'])
51
            ? $checksumInfo['responseAlgorithms']
52
            : [];
53
        if (empty($responseAlgorithms)
54
            || strtolower($checksumModeEnabled) !== "enabled"
55
        ) {
56
            return $result;
57
        }
58
 
59
        if (extension_loaded('awscrt')) {
60
            $checksumPriority = ['CRC32C', 'CRC32', 'SHA1', 'SHA256'];
61
        } else {
62
            $checksumPriority = ['CRC32', 'SHA1', 'SHA256'];
63
        }
64
        $checksumsToCheck = array_intersect($responseAlgorithms, $checksumPriority);
65
        $checksumValidationInfo = $this->validateChecksum($checksumsToCheck, $response);
66
 
67
        if ($checksumValidationInfo['status'] == "SUCCEEDED") {
68
            $result['ChecksumValidated'] = $checksumValidationInfo['checksum'];
69
        } else if ($checksumValidationInfo['status'] == "FAILED"){
70
            //Ignore failed validations on GetObject if it's a multipart get which returned a full multipart object
71
            if ($command->getName() == "GetObject"
72
                && !empty($checksumValidationInfo['checksumHeaderValue'])
73
            ) {
74
                $headerValue = $checksumValidationInfo['checksumHeaderValue'];
75
                $lastDashPos = strrpos($headerValue, '-');
76
                $endOfChecksum = substr($headerValue, $lastDashPos + 1);
77
                if (is_numeric($endOfChecksum)
78
                    && intval($endOfChecksum) > 1
79
                    && intval($endOfChecksum) < 10000) {
80
                    return $result;
81
                }
82
            }
83
            throw new S3Exception(
84
                "Calculated response checksum did not match the expected value",
85
                $command
86
            );
87
        }
88
        return $result;
89
    }
90
 
91
    public function parseMemberFromStream(
92
        StreamInterface $stream,
93
        StructureShape $member,
94
        $response
95
    ) {
96
        return $this->parser->parseMemberFromStream($stream, $member, $response);
97
    }
98
 
99
    /**
100
     * @param $checksumPriority
101
     * @param ResponseInterface $response
102
     */
103
    public function validateChecksum($checksumPriority, ResponseInterface $response)
104
    {
105
        $checksumToValidate = $this->chooseChecksumHeaderToValidate(
106
            $checksumPriority,
107
            $response
108
        );
109
        $validationStatus = "SKIPPED";
110
        $checksumHeaderValue = null;
111
        if (!empty($checksumToValidate)) {
112
            $checksumHeaderValue = $response->getHeader(
113
                'x-amz-checksum-' . $checksumToValidate
114
            );
115
            if (isset($checksumHeaderValue)) {
116
                $checksumHeaderValue = $checksumHeaderValue[0];
117
                $calculatedChecksumValue = $this->getEncodedValue(
118
                    $checksumToValidate,
119
                    $response->getBody()
120
                );
121
                $validationStatus = $checksumHeaderValue == $calculatedChecksumValue
122
                    ? "SUCCEEDED"
123
                    : "FAILED";
124
            }
125
        }
126
        return [
127
            "status" => $validationStatus,
128
            "checksum" => $checksumToValidate,
129
            "checksumHeaderValue" => $checksumHeaderValue,
130
        ];
131
    }
132
 
133
    /**
134
     * @param $checksumPriority
135
     * @param ResponseInterface $response
136
     */
137
    public function chooseChecksumHeaderToValidate(
138
        $checksumPriority,
139
        ResponseInterface $response
140
    ) {
141
        foreach ($checksumPriority as $checksum) {
142
            $checksumHeader = 'x-amz-checksum-' . $checksum;
143
            if ($response->hasHeader($checksumHeader)) {
144
                return $checksum;
145
            }
146
        }
147
        return null;
148
    }
149
}