Skip to content

Commit

Permalink
Updating checksum middlewares and related API docs for S3 and Glacier.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremeamia committed Jun 29, 2015
1 parent 3a2d520 commit e671f28
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 24 deletions.
36 changes: 27 additions & 9 deletions src/Glacier/GlacierClient.php
Expand Up @@ -59,9 +59,15 @@ private function getChecksumsMiddleware()
CommandInterface $command,
RequestInterface $request = null
) use ($handler) {
// Accept "ContentSHA256" with a lowercase "c" to match other Glacier params.
if (!$command['ContentSHA256'] && $command['contentSHA256']) {
$command['ContentSHA256'] = $command['contentSHA256'];
unset($command['contentSHA256']);
}

// If uploading, then make sure checksums are added.
$name = $command->getName();
if (($name === 'UploadArchive' || $name === 'UploadPart')
if (($name === 'UploadArchive' || $name === 'UploadMultipartPart')
&& (!$command['checksum'] || !$command['ContentSHA256'])
) {
$body = $request->getBody();
Expand Down Expand Up @@ -141,17 +147,29 @@ public static function applyDocFilters(array $api, array $docs)
// Add the SourceFile parameter.
$docs['shapes']['SourceFile']['base'] = 'The path to a file on disk to use instead of the body parameter.';
$api['shapes']['SourceFile'] = ['type' => 'string'];
$api['shapes']['UploadArchiveInput']['members']['SourceFile'] = ['shape' => 'SourceFile'];
$api['shapes']['UploadMultipartPartInput']['members']['SourceFile'] = ['shape' => 'SourceFile'];
$api['shapes']['UploadArchiveInput']['members']['sourceFile'] = ['shape' => 'SourceFile'];
$api['shapes']['UploadMultipartPartInput']['members']['sourceFile'] = ['shape' => 'SourceFile'];

// Add information about "checksum" being optional.
$docs['shapes']['checksum']['append'] =
'<div class="alert alert-info">The SDK will compute this value '
// Add the ContentSHA256 parameter.
$docs['shapes']['ContentSHA256']['base'] = 'A SHA256 hash of the content of the request body';
$api['shapes']['ContentSHA256'] = ['type' => 'string'];
$api['shapes']['UploadArchiveInput']['members']['contentSHA256'] = ['shape' => 'ContentSHA256'];
$api['shapes']['UploadMultipartPartInput']['members']['contentSHA256'] = ['shape' => 'ContentSHA256'];

// Add information about "checksum" and "ContentSHA256" being optional.
$optional = '<div class="alert alert-info">The SDK will compute this value '
. 'for you on your behalf if it is not supplied.</div>';
$docs['shapes']['checksum']['append'] = $optional;
$docs['shapes']['ContentSHA256']['append'] = $optional;

// Add information about "accountId" being optional.
$optional = '<div class="alert alert-info">The SDK will set this value '
. 'to "-" by default.</div>';
// Make "accountId" optional for all operations.
foreach ($api['operations'] as $operation) {
$inputShape =& $api['shapes'][$operation['input']['shape']];
$accountIdIndex = array_search('accountId', $inputShape['required']);
unset($inputShape['required'][$accountIdIndex]);
}
// Add information about the default value for "accountId".
$optional = '<div class="alert alert-info">The SDK will set this value to "-" by default.</div>';
foreach ($docs['shapes']['string']['refs'] as $name => &$ref) {
if (strpos($name, 'accountId')) {
$ref .= $optional;
Expand Down
Expand Up @@ -2,7 +2,6 @@
namespace Aws\S3;

use Aws\CommandInterface;
use Aws\Exception\CouldNotCreateChecksumException;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;

Expand All @@ -13,16 +12,21 @@
*
* @internal
*/
class ApplyMd5Middleware
class ApplyChecksumMiddleware
{
private static $requireMd5 = [
private static $md5 = [
'DeleteObjects',
'PutBucketCors',
'PutBucketLifecycle',
'PutBucketPolicy',
'PutBucketTagging',
];

private static $sha256 = [
'PutObject',
'UploadPart',
];

private $nextHandler;

/**
Expand All @@ -46,19 +50,24 @@ public function __invoke(
CommandInterface $command,
RequestInterface $request
) {
$next = $this->nextHandler;
$name = $command->getName();
$body = $request->getBody();
if (!$request->hasHeader('Content-MD5')
&& $body->getSize()
&& in_array($name, self::$requireMd5)
) {

if (in_array($name, self::$md5) && !$request->hasHeader('Content-MD5')) {
// Set the content MD5 header for operations that require it.
$request = $request->withHeader(
'Content-MD5',
base64_encode(Psr7\hash($body, 'md5', true))
);
} elseif (in_array($name, self::$sha256) && $command['ContentSHA256']) {
// Set the content hash header if provided in the parameters.
$request = $request->withHeader(
'X-Amz-Content-Sha256',
$command['ContentSHA256']
);
}

$next = $this->nextHandler;
return $next($command, $request);
}
}
18 changes: 13 additions & 5 deletions src/S3/S3Client.php
Expand Up @@ -62,7 +62,7 @@ public function __construct(array $args)
parent::__construct($args);
$stack = $this->getHandlerList();
$stack->appendInit(SSECMiddleware::wrap($this->getEndpoint()->getScheme()), 's3.ssec');
$stack->appendBuild(ApplyMd5Middleware::wrap(), 's3.md5');
$stack->appendBuild(ApplyChecksumMiddleware::wrap(), 's3.checksum');
$stack->appendBuild(
Middleware::contentType(['PutObject', 'UploadPart']),
's3.content_type'
Expand Down Expand Up @@ -503,15 +503,24 @@ public static function _applyApiProvider($value, array &$args, HandlerList $list
*/
public static function applyDocFilters(array $api, array $docs)
{
$b64 = '<div class="alert alert-info">This value will be base64 '
. 'encoded on your behalf.</div>';
$b64 = '<div class="alert alert-info">This value will be base64 encoded on your behalf.</div>';
$opt = '<div class="alert alert-info">This value will be computed for you it is not supplied.</div>';

// Add the SourceFile parameter.
$docs['shapes']['SourceFile']['base'] = 'The path to a file on disk to use instead of the Body parameter.';
$api['shapes']['SourceFile'] = ['type' => 'string'];
$api['shapes']['PutObjectRequest']['members']['SourceFile'] = ['shape' => 'SourceFile'];
$api['shapes']['UploadPartRequest']['members']['SourceFile'] = ['shape' => 'SourceFile'];

// Add the ContentSHA256 parameter.
$docs['shapes']['ContentSHA256']['base'] = 'A SHA256 hash of the body content of the request.';
$api['shapes']['ContentSHA256'] = ['type' => 'string'];
$api['shapes']['PutObjectRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256'];
$api['shapes']['UploadPartRequest']['members']['ContentSHA256'] = ['shape' => 'ContentSHA256'];
unset($api['shapes']['PutObjectRequest']['members']['ContentMD5']);
unset($api['shapes']['UploadPartRequest']['members']['ContentMD5']);
$docs['shapes']['ContentSHA256']['append'] = $opt;

// Add the SaveAs parameter.
$docs['shapes']['SaveAs']['base'] = 'The path to a file on disk to save the object data.';
$api['shapes']['SaveAs'] = ['type' => 'string'];
Expand All @@ -520,8 +529,7 @@ public static function applyDocFilters(array $api, array $docs)
// Several SSECustomerKey documentation updates.
$docs['shapes']['SSECustomerKey']['append'] = $b64;
$docs['shapes']['CopySourceSSECustomerKey']['append'] = $b64;
$docs['shapes']['SSECustomerKeyMd5']['append'] = '<div class="alert alert-info">The value will be computed on '
. 'your behalf if it is not supplied.</div>';
$docs['shapes']['SSECustomerKeyMd5']['append'] = $opt;

// Add the ObjectURL to various output shapes and documentation.
$docs['shapes']['ObjectURL']['base'] = 'The URI of the created object.';
Expand Down
Expand Up @@ -7,9 +7,9 @@
use Psr\Http\Message\RequestInterface;

/**
* @covers Aws\S3\ApplyMd5Middleware
* @covers Aws\S3\ApplyChecksumMiddleware
*/
class ApplyMd5MiddlewareTest extends \PHPUnit_Framework_TestCase
class ApplyChecksumMiddlewareTest extends \PHPUnit_Framework_TestCase
{
use UsesServiceTrait;

Expand Down Expand Up @@ -61,4 +61,50 @@ public function getContentMd5UseCases()
],
];
}

/**
* @dataProvider getContentSha256UseCases
*/
public function testAddsContentSHA256AsAppropriate($operation, $args, $hashAdded, $hashValue)
{
$s3 = $this->getTestClient('s3');
$this->addMockResults($s3, [[]]);
$command = $s3->getCommand($operation, $args);
$command->getHandlerList()->appendBuild(
Middleware::tap(function ($cmd, RequestInterface $request) use ($hashAdded, $hashValue) {
$this->assertSame($hashAdded, $request->hasHeader('x-amz-content-sha256'));
$this->assertEquals($hashValue, $request->getHeaderLine('x-amz-content-sha256'));
})
);
$s3->execute($command);
}

public function getContentSha256UseCases()
{
$hash = 'SHA256HASH';

return [
// Do nothing if ContentSHA256 was not provided.
[
'PutObject',
['Bucket' => 'foo', 'Key' => 'bar', 'Body' => 'baz'],
false,
''
],
// Gets added for operations that allow it.
[
'PutObject',
['Bucket' => 'foo', 'Key' => 'bar', 'Body' => 'baz', 'ContentSHA256' => $hash],
true,
$hash
],
// Not added for operations that do not allow it.
[
'GetObject',
['Bucket' => 'foo', 'Key' => 'bar', 'ContentSHA256' => $hash],
false,
'',
],
];
}
}

0 comments on commit e671f28

Please sign in to comment.