diff options
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/S3/ValidateResponseChecksumParser.php')
-rw-r--r-- | vendor/aws/aws-sdk-php/src/S3/ValidateResponseChecksumParser.php | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/S3/ValidateResponseChecksumParser.php b/vendor/aws/aws-sdk-php/src/S3/ValidateResponseChecksumParser.php new file mode 100644 index 0000000..d63c407 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/ValidateResponseChecksumParser.php @@ -0,0 +1,149 @@ +<?php +namespace Aws\S3; + +use Aws\Api\Parser\AbstractParser; +use Aws\Api\Service; +use Aws\Api\StructureShape; +use Aws\CommandInterface; +use Aws\S3\Exception\S3Exception; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; + +/** + * @internal Decorates a parser for the S3 service to validate the response checksum. + */ +class ValidateResponseChecksumParser extends AbstractParser +{ + use CalculatesChecksumTrait; + /** + * @param callable $parser Parser to wrap. + */ + public function __construct(callable $parser, Service $api) + { + $this->api = $api; + $this->parser = $parser; + } + + public function __invoke( + CommandInterface $command, + ResponseInterface $response + ) { + $fn = $this->parser; + $result = $fn($command, $response); + + //Skip this middleware if the operation doesn't have an httpChecksum + $op = $this->api->getOperation($command->getName()); + $checksumInfo = isset($op['httpChecksum']) + ? $op['httpChecksum'] + : []; + if (empty($checksumInfo)) { + return $result; + } + + //Skip this middleware if the operation doesn't send back a checksum, or the user doesn't opt in + $checksumModeEnabledMember = isset($checksumInfo['requestValidationModeMember']) + ? $checksumInfo['requestValidationModeMember'] + : ""; + $checksumModeEnabled = isset($command[$checksumModeEnabledMember]) + ? $command[$checksumModeEnabledMember] + : ""; + $responseAlgorithms = isset($checksumInfo['responseAlgorithms']) + ? $checksumInfo['responseAlgorithms'] + : []; + if (empty($responseAlgorithms) + || strtolower($checksumModeEnabled) !== "enabled" + ) { + return $result; + } + + if (extension_loaded('awscrt')) { + $checksumPriority = ['CRC32C', 'CRC32', 'SHA1', 'SHA256']; + } else { + $checksumPriority = ['CRC32', 'SHA1', 'SHA256']; + } + $checksumsToCheck = array_intersect($responseAlgorithms, $checksumPriority); + $checksumValidationInfo = $this->validateChecksum($checksumsToCheck, $response); + + if ($checksumValidationInfo['status'] == "SUCCEEDED") { + $result['ChecksumValidated'] = $checksumValidationInfo['checksum']; + } else if ($checksumValidationInfo['status'] == "FAILED"){ + //Ignore failed validations on GetObject if it's a multipart get which returned a full multipart object + if ($command->getName() == "GetObject" + && !empty($checksumValidationInfo['checksumHeaderValue']) + ) { + $headerValue = $checksumValidationInfo['checksumHeaderValue']; + $lastDashPos = strrpos($headerValue, '-'); + $endOfChecksum = substr($headerValue, $lastDashPos + 1); + if (is_numeric($endOfChecksum) + && intval($endOfChecksum) > 1 + && intval($endOfChecksum) < 10000) { + return $result; + } + } + throw new S3Exception( + "Calculated response checksum did not match the expected value", + $command + ); + } + return $result; + } + + public function parseMemberFromStream( + StreamInterface $stream, + StructureShape $member, + $response + ) { + return $this->parser->parseMemberFromStream($stream, $member, $response); + } + + /** + * @param $checksumPriority + * @param ResponseInterface $response + */ + public function validateChecksum($checksumPriority, ResponseInterface $response) + { + $checksumToValidate = $this->chooseChecksumHeaderToValidate( + $checksumPriority, + $response + ); + $validationStatus = "SKIPPED"; + $checksumHeaderValue = null; + if (!empty($checksumToValidate)) { + $checksumHeaderValue = $response->getHeader( + 'x-amz-checksum-' . $checksumToValidate + ); + if (isset($checksumHeaderValue)) { + $checksumHeaderValue = $checksumHeaderValue[0]; + $calculatedChecksumValue = $this->getEncodedValue( + $checksumToValidate, + $response->getBody() + ); + $validationStatus = $checksumHeaderValue == $calculatedChecksumValue + ? "SUCCEEDED" + : "FAILED"; + } + } + return [ + "status" => $validationStatus, + "checksum" => $checksumToValidate, + "checksumHeaderValue" => $checksumHeaderValue, + ]; + } + + /** + * @param $checksumPriority + * @param ResponseInterface $response + */ + public function chooseChecksumHeaderToValidate( + $checksumPriority, + ResponseInterface $response + ) { + foreach ($checksumPriority as $checksum) { + $checksumHeader = 'x-amz-checksum-' . $checksum; + if ($response->hasHeader($checksumHeader)) { + return $checksum; + } + } + return null; + } +} |