AutorÃa | Ultima modificación | Ver Log |
<?phpnamespace 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 objectif ($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;}}