/usr/share/php/Aws/S3/ResumableDownload.php is in php-aws-sdk 2.7.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | <?php
/**
* Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
namespace Aws\S3;
use Aws\Common\Exception\RuntimeException;
use Aws\Common\Exception\UnexpectedValueException;
use Guzzle\Http\EntityBody;
use Guzzle\Http\ReadLimitEntityBody;
use Guzzle\Http\EntityBodyInterface;
use Guzzle\Service\Resource\Model;
/**
* Allows you to resume the download of a partially downloaded object.
*
* Downloads objects from Amazon S3 in using "Range" downloads. This allows a partially downloaded object to be resumed
* so that only the remaining portion of the object is downloaded.
*/
class ResumableDownload
{
/** @var S3Client The S3 client to use to download objects and issue HEAD requests */
protected $client;
/** @var \Guzzle\Service\Resource\Model Model object returned when the initial HeadObject operation was called */
protected $meta;
/** @var array Array of parameters to pass to a GetObject operation */
protected $params;
/** @var \Guzzle\Http\EntityBody Where the object will be downloaded */
protected $target;
/**
* @param S3Client $client Client to use when executing requests
* @param string $bucket Bucket that holds the object
* @param string $key Key of the object
* @param string|resource|EntityBodyInterface $target Where the object should be downloaded to. Pass a string to
* save the object to a file, pass a resource returned by
* fopen() to save the object to a stream resource, or pass a
* Guzzle EntityBody object to save the contents to an
* EntityBody.
* @param array $params Any additional GetObject or HeadObject parameters to use
* with each command issued by the client. (e.g. pass "Version"
* to download a specific version of an object)
* @throws RuntimeException if the target variable points to a file that cannot be opened
*/
public function __construct(S3Client $client, $bucket, $key, $target, array $params = array())
{
$this->params = $params;
$this->client = $client;
$this->params['Bucket'] = $bucket;
$this->params['Key'] = $key;
// If a string is passed, then assume that the download should stream to a file on disk
if (is_string($target)) {
if (!($target = fopen($target, 'a+'))) {
throw new RuntimeException("Unable to open {$target} for writing");
}
// Always append to the file
fseek($target, 0, SEEK_END);
}
// Get the metadata and Content-MD5 of the object
$this->target = EntityBody::factory($target);
}
/**
* Get the bucket of the download
*
* @return string
*/
public function getBucket()
{
return $this->params['Bucket'];
}
/**
* Get the key of the download
*
* @return string
*/
public function getKey()
{
return $this->params['Key'];
}
/**
* Get the file to which the contents are downloaded
*
* @return string
*/
public function getFilename()
{
return $this->target->getUri();
}
/**
* Download the remainder of the object from Amazon S3
*
* Performs a message integrity check if possible
*
* @return Model
*/
public function __invoke()
{
$command = $this->client->getCommand('HeadObject', $this->params);
$this->meta = $command->execute();
if ($this->target->ftell() >= $this->meta['ContentLength']) {
return false;
}
$this->meta['ContentMD5'] = (string) $command->getResponse()->getHeader('Content-MD5');
// Use a ReadLimitEntityBody so that rewinding the stream after an error does not cause the file pointer
// to enter an inconsistent state with the data being downloaded
$this->params['SaveAs'] = new ReadLimitEntityBody(
$this->target,
$this->meta['ContentLength'],
$this->target->ftell()
);
$result = $this->getRemaining();
$this->checkIntegrity();
return $result;
}
/**
* Send the command to get the remainder of the object
*
* @return Model
*/
protected function getRemaining()
{
$current = $this->target->ftell();
$targetByte = $this->meta['ContentLength'] - 1;
$this->params['Range'] = "bytes={$current}-{$targetByte}";
// Set the starting offset so that the body is never seeked to before this point in the event of a retry
$this->params['SaveAs']->setOffset($current);
$command = $this->client->getCommand('GetObject', $this->params);
return $command->execute();
}
/**
* Performs an MD5 message integrity check if possible
*
* @throws UnexpectedValueException if the message does not validate
*/
protected function checkIntegrity()
{
if ($this->target->isReadable() && $expected = $this->meta['ContentMD5']) {
$actual = $this->target->getContentMd5();
if ($actual != $expected) {
throw new UnexpectedValueException(
"Message integrity check failed. Expected {$expected} but got {$actual}."
);
}
}
}
}
|