Commit 1be5a3ca authored by Lukas Reschke's avatar Lukas Reschke
Browse files

Merge pull request #12166 from helmutschneider/aws-2.7.5

Upgrade AWS sdk to 2.7.5. Fixes #12023
parents 116a1b36 e0056c4a
......@@ -28,7 +28,7 @@ class Aws extends ServiceBuilder
/**
* @var string Current version of the SDK
*/
const VERSION = '2.6.15';
const VERSION = '2.7.5';
/**
* Create a new service locator for the AWS SDK
......
......@@ -17,7 +17,6 @@
namespace Aws\Common\Client;
use Aws\Common\Aws;
use Aws\Common\Credentials\Credentials;
use Aws\Common\Credentials\CredentialsInterface;
use Aws\Common\Credentials\NullCredentials;
use Aws\Common\Enum\ClientOptions as Options;
......@@ -111,13 +110,7 @@ abstract class AbstractClient extends Client implements AwsClientInterface
/**
* Get an endpoint for a specific region from a service description
*
* @param ServiceDescriptionInterface $description Service description
* @param string $region Region of the endpoint
* @param string $scheme URL scheme
*
* @return string
* @throws InvalidArgumentException
* @deprecated This function will no longer be updated to work with new regions.
*/
public static function getEndpoint(ServiceDescriptionInterface $description, $region, $scheme)
{
......@@ -177,12 +170,27 @@ abstract class AbstractClient extends Client implements AwsClientInterface
$config = $this->getConfig();
$formerRegion = $config->get(Options::REGION);
$global = $this->serviceDescription->getData('globalEndpoint');
$provider = $config->get('endpoint_provider');
if (!$provider) {
throw new \RuntimeException('No endpoint provider configured');
}
// Only change the region if the service does not have a global endpoint
if (!$global || $this->serviceDescription->getData('namespace') === 'S3') {
$baseUrl = self::getEndpoint($this->serviceDescription, $region, $config->get(Options::SCHEME));
$this->setBaseUrl($baseUrl);
$config->set(Options::BASE_URL, $baseUrl)->set(Options::REGION, $region);
$endpoint = call_user_func(
$provider,
array(
'scheme' => $config->get(Options::SCHEME),
'region' => $region,
'service' => $config->get(Options::SERVICE)
)
);
$this->setBaseUrl($endpoint['endpoint']);
$config->set(Options::BASE_URL, $endpoint['endpoint']);
$config->set(Options::REGION, $region);
// Update the signature if necessary
$signature = $this->getSignature();
......
......@@ -20,13 +20,13 @@ use Aws\Common\Credentials\Credentials;
use Aws\Common\Credentials\CredentialsInterface;
use Aws\Common\Credentials\NullCredentials;
use Aws\Common\Enum\ClientOptions as Options;
use Aws\Common\Enum\Region;
use Aws\Common\Exception\ExceptionListener;
use Aws\Common\Exception\InvalidArgumentException;
use Aws\Common\Exception\NamespaceExceptionFactory;
use Aws\Common\Exception\Parser\DefaultXmlExceptionParser;
use Aws\Common\Exception\Parser\ExceptionParserInterface;
use Aws\Common\Iterator\AwsResourceIteratorFactory;
use Aws\Common\RulesEndpointProvider;
use Aws\Common\Signature\EndpointSignatureInterface;
use Aws\Common\Signature\SignatureInterface;
use Aws\Common\Signature\SignatureV2;
......@@ -38,7 +38,6 @@ use Guzzle\Plugin\Backoff\CurlBackoffStrategy;
use Guzzle\Plugin\Backoff\ExponentialBackoffStrategy;
use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
use Guzzle\Plugin\Backoff\TruncatedBackoffStrategy;
use Guzzle\Service\Client;
use Guzzle\Service\Description\ServiceDescription;
use Guzzle\Service\Resource\ResourceIteratorClassFactory;
use Guzzle\Log\LogAdapterInterface;
......@@ -200,6 +199,10 @@ class ClientBuilder
(self::$commonConfigRequirements + $this->configRequirements)
);
if (!isset($config['endpoint_provider'])) {
$config['endpoint_provider'] = RulesEndpointProvider::fromDefaults();
}
// Resolve the endpoint, signature, and credentials
$description = $this->updateConfigFromDescription($config);
$signature = $this->getSignature($description, $config);
......@@ -366,33 +369,36 @@ class ClientBuilder
$this->setIteratorsConfig($iterators);
}
// Ensure that the service description has regions
if (!$description->getData('regions')) {
throw new InvalidArgumentException(
'No regions found in the ' . $description->getData('serviceFullName'). ' description'
);
}
// Make sure a valid region is set
$region = $config->get(Options::REGION);
$global = $description->getData('globalEndpoint');
if (!$global && !$region) {
throw new InvalidArgumentException(
'A region is required when using ' . $description->getData('serviceFullName')
. '. Set "region" to one of: ' . implode(', ', array_keys($description->getData('regions')))
);
} elseif ($global && (!$region || $description->getData('namespace') !== 'S3')) {
$region = Region::US_EAST_1;
$config->set(Options::REGION, $region);
$region = 'us-east-1';
$config->set(Options::REGION, 'us-east-1');
}
if (!$config->get(Options::BASE_URL)) {
// Set the base URL using the scheme and hostname of the service's region
$config->set(Options::BASE_URL, AbstractClient::getEndpoint(
$description,
$region,
$config->get(Options::SCHEME)
));
$endpoint = call_user_func(
$config->get('endpoint_provider'),
array(
'scheme' => $config->get(Options::SCHEME),
'region' => $region,
'service' => $config->get(Options::SERVICE)
)
);
$config->set(Options::BASE_URL, $endpoint['endpoint']);
// Set a signature if one was not explicitly provided.
if (!$config->hasKey(Options::SIGNATURE)
&& isset($endpoint['signatureVersion'])
) {
$config->set(Options::SIGNATURE, $endpoint['signatureVersion']);
}
}
return $description;
......
......@@ -39,6 +39,9 @@ class Region extends Enum
const EU_WEST_1 = 'eu-west-1';
const IRELAND = 'eu-west-1';
const EU_CENTRAL_1 = 'eu-central-1';
const FRANKFURT = 'eu-central-1';
const AP_SOUTHEAST_1 = 'ap-southeast-1';
const SINGAPORE = 'ap-southeast-1';
......
......@@ -38,6 +38,10 @@ class HashUtils
$useNative = function_exists('hex2bin');
}
if (!$useNative && strlen($hash) % 2 !== 0) {
$hash = '0' . $hash;
}
return $useNative ? hex2bin($hash) : pack("H*", $hash);
}
......
......@@ -49,7 +49,7 @@ abstract class AbstractUploadBuilder
/**
* Return a new instance of the UploadBuilder
*
* @return self
* @return static
*/
public static function newInstance()
{
......@@ -61,7 +61,7 @@ abstract class AbstractUploadBuilder
*
* @param AwsClientInterface $client Client to use
*
* @return self
* @return $this
*/
public function setClient(AwsClientInterface $client)
{
......@@ -78,7 +78,7 @@ abstract class AbstractUploadBuilder
* multipart upload. When an ID is passed, the builder will create a
* state object using the data from a ListParts API response.
*
* @return self
* @return $this
*/
public function resumeFrom($state)
{
......@@ -94,7 +94,7 @@ abstract class AbstractUploadBuilder
* You can also stream from a resource returned from fopen or a Guzzle
* {@see EntityBody} object.
*
* @return self
* @return $this
* @throws InvalidArgumentException when the source cannot be found or opened
*/
public function setSource($source)
......@@ -123,7 +123,7 @@ abstract class AbstractUploadBuilder
*
* @param array $headers Headers to add to the uploaded object
*
* @return self
* @return $this
*/
public function setHeaders(array $headers)
{
......
......@@ -78,6 +78,12 @@ return array(
'class' => 'Aws\CloudWatch\CloudWatchClient'
),
'cloudwatchlogs' => array(
'alias' => 'CloudWatchLogs',
'extends' => 'default_settings',
'class' => 'Aws\CloudWatchLogs\CloudWatchLogsClient'
),
'cognito-identity' => array(
'alias' => 'CognitoIdentity',
'extends' => 'default_settings',
......@@ -94,10 +100,16 @@ return array(
'cognitosync' => array('extends' => 'cognito-sync'),
'cloudwatchlogs' => array(
'alias' => 'CloudWatchLogs',
'codedeploy' => array(
'alias' => 'CodeDeploy',
'extends' => 'default_settings',
'class' => 'Aws\CloudWatchLogs\CloudWatchLogsClient'
'class' => 'Aws\CodeDeploy\CodeDeployClient'
),
'config' => array(
'alias' => 'ConfigService',
'extends' => 'default_settings',
'class' => 'Aws\ConfigService\ConfigServiceClient'
),
'datapipeline' => array(
......@@ -173,6 +185,18 @@ return array(
'class' => 'Aws\Kinesis\KinesisClient'
),
'kms' => array(
'alias' => 'Kms',
'extends' => 'default_settings',
'class' => 'Aws\Kms\KmsClient'
),
'lambda' => array(
'alias' => 'Lambda',
'extends' => 'default_settings',
'class' => 'Aws\Lambda\LambdaClient'
),
'iam' => array(
'alias' => 'Iam',
'extends' => 'default_settings',
......
<?php
return array(
'version' => 2,
'endpoints' => array(
'*/*' => array(
'endpoint' => '{service}.{region}.amazonaws.com'
),
'cn-north-1/*' => array(
'endpoint' => '{service}.{region}.amazonaws.com.cn',
'signatureVersion' => 'v4'
),
'us-gov-west-1/iam' => array(
'endpoint' => 'iam.us-gov.amazonaws.com'
),
'us-gov-west-1/sts' => array(
'endpoint' => 'sts.us-gov.amazonaws.com'
),
'us-gov-west-1/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'*/cloudfront' => array(
'endpoint' => 'cloudfront.amazonaws.com'
),
'*/iam' => array(
'endpoint' => 'iam.amazonaws.com'
),
'*/importexport' => array(
'endpoint' => 'importexport.amazonaws.com'
),
'*/route53' => array(
'endpoint' => 'route53.amazonaws.com'
),
'*/sts' => array(
'endpoint' => 'sts.amazonaws.com'
),
'us-east-1/sdb' => array(
'endpoint' => 'sdb.amazonaws.com'
),
'us-east-1/s3' => array(
'endpoint' => 's3.amazonaws.com'
),
'us-west-1/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'us-west-2/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'eu-west-1/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'ap-southeast-1/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'ap-southeast-2/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'ap-northeast-1/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
),
'sa-east-1/s3' => array(
'endpoint' => 's3-{region}.amazonaws.com'
)
)
);
<?php
namespace Aws\Common;
/**
* Provides endpoints based on a rules configuration file.
*/
class RulesEndpointProvider
{
/** @var array */
private $patterns;
/**
* @param array $patterns Hash of endpoint patterns mapping to endpoint
* configurations.
*/
public function __construct(array $patterns)
{
$this->patterns = $patterns;
}
/**
* Creates and returns the default RulesEndpointProvider based on the
* public rule sets.
*
* @return self
*/
public static function fromDefaults()
{
return new self(require __DIR__ . '/Resources/public-endpoints.php');
}
public function __invoke(array $args = array())
{
if (!isset($args['service'])) {
throw new \InvalidArgumentException('Requires a "service" value');
}
if (!isset($args['region'])) {
throw new \InvalidArgumentException('Requires a "region" value');
}
foreach ($this->getKeys($args['region'], $args['service']) as $key) {
if (isset($this->patterns['endpoints'][$key])) {
return $this->expand($this->patterns['endpoints'][$key], $args);
}
}
throw new \RuntimeException('Could not resolve endpoint');
}
private function expand(array $config, array $args)
{
$scheme = isset($args['scheme']) ? $args['scheme'] : 'https';
$config['endpoint'] = $scheme . '://' . str_replace(
array('{service}', '{region}'),
array($args['service'], $args['region']),
$config['endpoint']
);
return $config;
}
private function getKeys($region, $service)
{
return array("$region/$service", "$region/*", "*/$service", "*/*");
}
}
......@@ -19,7 +19,6 @@ namespace Aws\Common\Signature;
use Aws\Common\Credentials\CredentialsInterface;
use Aws\Common\Enum\DateFormat;
use Aws\Common\HostNameUtils;
use Guzzle\Http\Message\EntityEnclosingRequest;
use Guzzle\Http\Message\EntityEnclosingRequestInterface;
use Guzzle\Http\Message\RequestFactory;
use Guzzle\Http\Message\RequestInterface;
......@@ -304,43 +303,42 @@ class SignatureV4 extends AbstractSignature implements EndpointSignatureInterfac
*/
private function createSigningContext(RequestInterface $request, $payload)
{
$signable = array(
'host' => true,
'date' => true,
'content-md5' => true
);
// Normalize the path as required by SigV4 and ensure it's absolute
$canon = $request->getMethod() . "\n"
. $this->createCanonicalizedPath($request) . "\n"
. $this->getCanonicalizedQueryString($request) . "\n";
// Create the canonical headers
$headers = array();
$canonHeaders = array();
foreach ($request->getHeaders()->getAll() as $key => $values) {
$key = strtolower($key);
if ($key != 'user-agent') {
$headers[$key] = array();
foreach ($values as $value) {
$headers[$key][] = preg_replace('/\s+/', ' ', trim($value));
}
// Sort the value if there is more than one
if (count($values) > 1) {
sort($headers[$key]);
if (isset($signable[$key]) || substr($key, 0, 6) === 'x-amz-') {
$values = $values->toArray();
if (count($values) == 1) {
$values = $values[0];
} else {
sort($values);
$values = implode(',', $values);
}
$canonHeaders[$key] = $key . ':' . preg_replace('/\s+/', ' ', $values);
}
}
// The headers must be sorted
ksort($headers);
// Continue to build the canonical request by adding headers
foreach ($headers as $key => $values) {
// Combine multi-value headers into a comma separated list
$canon .= $key . ':' . implode(',', $values) . "\n";
}
// Create the signed headers
$signedHeaders = implode(';', array_keys($headers));
$canon .= "\n{$signedHeaders}\n{$payload}";
ksort($canonHeaders);
$signedHeadersString = implode(';', array_keys($canonHeaders));
$canon .= implode("\n", $canonHeaders) . "\n\n"
. $signedHeadersString . "\n"
. $payload;
return array(
'canonical_request' => $canon,
'signed_headers' => $signedHeaders
'signed_headers' => $signedHeadersString
);
}
......@@ -394,6 +392,8 @@ class SignatureV4 extends AbstractSignature implements EndpointSignatureInterfac
foreach ($queryParams as $key => $values) {
if (is_array($values)) {
sort($values);
} elseif ($values === 0) {
$values = array('0');
} elseif (!$values) {
$values = array('');
}
......
......@@ -54,7 +54,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable
*
* @param array $data Array of ACP data
*
* @return self
* @return Acp
*/
public static function fromArray(array $data)
{
......@@ -100,7 +100,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable
*
* @param Grantee $owner ACP policy owner
*
* @return self
* @return $this
*
* @throws InvalidArgumentException if the grantee does not have an ID set
*/
......@@ -130,7 +130,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable
*
* @param array|\Traversable $grants List of grants for the ACP
*
* @return self
* @return $this
*
* @throws InvalidArgumentException
*/
......@@ -167,7 +167,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable
*
* @param Grant $grant Grant to add
*
* @return self
* @return $this
*/
public function addGrant(Grant $grant)
{
......@@ -205,7 +205,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable
*
* @param AbstractCommand $command Command to be updated
*
* @return self
* @return $this
*/
public function updateCommand(AbstractCommand $command)
{
......
......@@ -36,11 +36,11 @@ class AcpBuilder
/**
* Static method for chainable instantiation
*
* @return self
* @return static
*/
public static function newInstance()
{
return new self;
return new static;
}
/**
......@@ -49,7 +49,7 @@ class AcpBuilder
* @param string $id Owner identifier
* @param string $displayName Owner display name
*
* @return self
* @return $this
*/
public function setOwner($id, $displayName = null)
{
......@@ -65,7 +65,7 @@ class AcpBuilder
* @param string $id Grantee identifier
* @param string $displayName Grantee display name
*
* @return self
* @return $this
*/
public function addGrantForUser($permission, $id, $displayName = null)
{
......@@ -81,7 +81,7 @@ class AcpBuilder
* @param string $permission Permission for the Grant
* @param string $email Grantee email address
*
* @return self
* @return $this
*/
public function addGrantForEmail($permission, $email)
{
......@@ -97,7 +97,7 @@ class AcpBuilder
* @param string $permission Permission for the Grant
* @param string $group Grantee group
*
* @return self
* @return $this
*/
public function addGrantForGroup($permission, $group)
{
......@@ -113,7 +113,7 @@ class AcpBuilder
* @param string $permission Permission for the Grant
* @param Grantee $grantee The Grantee for the Grant
*
* @return self
* @return $this
*/
public function addGrant($permission, Grantee $grantee)
{
......