Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: add request body compression support #2693

Merged
merged 30 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .changes/nextrelease/bugfix-crc32-flexible-checksum.json

This file was deleted.

7 changes: 7 additions & 0 deletions .changes/nextrelease/compression-trait.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"type": "feature",
"category": "",
"description": "Adds support for automatically compressing request bodies when a service supports it."
}
]
12 changes: 12 additions & 0 deletions src/AwsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ public function __construct(array $args)
$this->addInvocationId();
$this->addEndpointParameterMiddleware($args);
$this->addEndpointDiscoveryMiddleware($config, $args);
$this->addRequestCompressionMiddleware($config);
$this->loadAliases();
$this->addStreamRequestPayload();
$this->addRecursionDetection();
Expand Down Expand Up @@ -449,6 +450,17 @@ private function addSignatureMiddleware()
);
}

private function addRequestCompressionMiddleware($config)
{
if (empty($config['disable_request_compression'])) {
$list = $this->getHandlerList();
$list->appendBuild(
RequestCompressionMiddleware::wrap($config),
'request-compression'
);
}
}

private function addInvocationId()
{
// Add invocation id to each request
Expand Down
78 changes: 69 additions & 9 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
<?php
namespace Aws;

use Aws\Api\Validator;
use Aws\Api\ApiProvider;
use Aws\Api\Service;
use Aws\Api\Validator;
use Aws\ClientSideMonitoring\ApiCallAttemptMonitoringMiddleware;
use Aws\ClientSideMonitoring\ApiCallMonitoringMiddleware;
use Aws\ClientSideMonitoring\Configuration;
use Aws\Configuration\ConfigurationResolver;
use Aws\Credentials\CredentialProvider;
use Aws\Credentials\Credentials;
use Aws\Credentials\CredentialsInterface;
use Aws\DefaultsMode\ConfigurationInterface as ConfigModeInterface;
use Aws\DefaultsMode\ConfigurationProvider as ConfigModeProvider;
use Aws\Endpoint\EndpointProvider;
use Aws\Endpoint\PartitionEndpointProvider;
use Aws\Endpoint\UseFipsEndpoint\Configuration as UseFipsEndpointConfiguration;
use Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider as UseFipsConfigProvider;
use Aws\Endpoint\UseFipsEndpoint\ConfigurationInterface as UseFipsEndpointConfigurationInterface;
use Aws\Endpoint\UseDualstackEndpoint\Configuration as UseDualStackEndpointConfiguration;
use Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider as UseDualStackConfigProvider;
use Aws\Endpoint\UseDualstackEndpoint\ConfigurationInterface as UseDualStackEndpointConfigurationInterface;
use Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider as UseDualStackConfigProvider;
use Aws\Endpoint\UseFipsEndpoint\Configuration as UseFipsEndpointConfiguration;
use Aws\Endpoint\UseFipsEndpoint\ConfigurationInterface as UseFipsEndpointConfigurationInterface;
use Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider as UseFipsConfigProvider;
use Aws\EndpointDiscovery\ConfigurationInterface;
use Aws\EndpointDiscovery\ConfigurationProvider;
use Aws\EndpointV2\EndpointDefinitionProvider;
use Aws\Exception\AwsException;
use Aws\Exception\InvalidRegionException;
use Aws\Retry\ConfigurationInterface as RetryConfigInterface;
use Aws\Retry\ConfigurationProvider as RetryConfigProvider;
use Aws\DefaultsMode\ConfigurationInterface as ConfigModeInterface;
use Aws\DefaultsMode\ConfigurationProvider as ConfigModeProvider;
use Aws\Signature\SignatureProvider;
use Aws\Endpoint\EndpointProvider;
use Aws\Token\Token;
use Aws\Token\TokenInterface;
use Aws\Token\TokenProvider;
use GuzzleHttp\Promise\PromiseInterface;
use Aws\Credentials\CredentialProvider;
use InvalidArgumentException as IAE;
use Psr\Http\Message\RequestInterface;

Expand Down Expand Up @@ -219,6 +220,20 @@ class ClientResolver
'doc' => 'Set to true to display debug information when sending requests. Alternatively, you can provide an associative array with the following keys: logfn: (callable) Function that is invoked with log messages; stream_size: (int) When the size of a stream is greater than this number, the stream data will not be logged (set to "0" to not log any stream data); scrub_auth: (bool) Set to false to disable the scrubbing of auth data from the logged messages; http: (bool) Set to false to disable the "debug" feature of lower level HTTP adapters (e.g., verbose curl output).',
'fn' => [__CLASS__, '_apply_debug'],
],
'disable_request_compression' => [
'type' => 'value',
'valid' => ['bool', 'callable'],
'doc' => 'Set to true to disable request compression for supported operations',
'fn' => [__CLASS__, '_apply_disable_request_compression'],
'default' => [__CLASS__, '_default_disable_request_compression'],
],
'request_min_compression_size_bytes' => [
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
'type' => 'value',
'valid' => ['int', 'callable'],
'doc' => 'Set to a value between between 0 and 10485760 bytes, inclusive. This value will be ignored if `disable_request_compression` is set to `true`',
'fn' => [__CLASS__, '_apply_min_compression_size'],
'default' => [__CLASS__, '_default_min_compression_size'],
],
'csm' => [
'type' => 'value',
'valid' => [\Aws\ClientSideMonitoring\ConfigurationInterface::class, 'callable', 'array', 'bool'],
Expand Down Expand Up @@ -520,6 +535,51 @@ public static function _apply_defaults($value, array &$args, HandlerList $list)
}
}

public static function _apply_disable_request_compression($value, array &$args) {
if (is_callable($value)) {
$value = $value();
}
if (!is_bool($value)) {
throw new IAE(
"Invalid configuration value provided for 'disable_request_compression'."
. " value must be a bool."
);
}
$args['config']['disable_request_compression'] = $value;
}

public static function _default_disable_request_compression(array &$args) {
return ConfigurationResolver::resolve(
'disable_request_compression',
false,
'bool',
$args
);
}

public static function _apply_min_compression_size($value, array &$args) {
if (is_callable($value)) {
$value = $value();
}
if (!is_int($value)
|| (is_int($value)
&& ($value < 0 || $value > 10485760))
) {
throw new IAE(" Invalid configuration value provided for 'min_compression_size_bytes'."
. " value must be an integer between 0 and 10485760, inclusive.");
}
$args['config']['request_min_compression_size_bytes'] = $value;
}

public static function _default_min_compression_size(array &$args) {
return ConfigurationResolver::resolve(
'request_min_compression_size_bytes',
10240,
'int',
$args
);
}

public static function _apply_credentials($value, array &$args)
{
if (is_callable($value)) {
Expand Down
180 changes: 180 additions & 0 deletions src/Configuration/ConfigurationResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php

namespace Aws\Configuration;

class ConfigurationResolver
{
const ENV_PROFILE = 'AWS_PROFILE';
const ENV_CONFIG_FILE = 'AWS_CONFIG_FILE';

public static $envPrefix = 'AWS_';

/**
* Generic configuration resolver that first checks for environment
* variables, then checks for a specified profile in the environment-defined
* config file location (env variable is 'AWS_CONFIG_FILE', file location
* defaults to ~/.aws/config), then checks for the "default" profile in the
* environment-defined config file location, and failing those uses a default
* fallback value.
*
* @param string $key Configuration key to be used when attempting
* to retrieve value from the environment or ini file.
* @param mixed $defaultValue
* @param string $expectedType The expected type of the retrieved value.
* @param array $config
* @param array $additionalArgs
*
* @return mixed
*/
public static function resolve(
$key,
$defaultValue,
$expectedType,
$config = []
)
{
$envValue = self::env($key, $expectedType);
if (!is_null($envValue)) {
return $envValue;
}

if (!isset($config['use_aws_shared_config_files'])
|| $config['use_aws_shared_config_files'] != false
) {
$iniValue = self::ini($key, $expectedType);
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
if(!is_null($iniValue)) {
return $iniValue;
}
}

return $defaultValue;
}

/**
* Resolves config values from environment variables.
*
* @param string $key Configuration key to be used when attempting
* to retrieve value from the environment.
* @param string $expectedType The expected type of the retrieved value.
*
* @return null | mixed
*/
public static function env($key, $expectedType)
{
// Use config from environment variables, if available
$envValue = getenv(self::$envPrefix . strtoupper($key));
if (!empty($envValue)) {
if ($expectedType) {
$envValue = self::convertType($envValue, $expectedType);
}
return $envValue;
}

return null;
}

/**
* Gets config values from a config file whose location
* is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to
* ~/.aws/config if not specified
*
*
* @param string $key Configuration key to be used when attempting
* to retrieve value from ini file.
* @param string $expectedType The expected type of the retrieved value.
* @param string|null $profile Profile to use. If not specified will use
* the "default" profile.
* @param string|null $filename If provided, uses a custom filename rather
* than looking in the default directory.
*
* @return null | mixed
*/
public static function ini($key, $expectedType, $profile = null, $filename = null)
{
$filename = $filename ?: (self::getDefaultConfigFilename());
$profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');

if (!@is_readable($filename)) {
return null;
}
// Use INI_SCANNER_NORMAL instead of INI_SCANNER_TYPED for PHP 5.5 compatibility
//TODO change after deprecation
$data = @\Aws\parse_ini_file($filename, true, INI_SCANNER_NORMAL);
if ($data === false
|| !isset($data[$profile])
|| !isset($data[$profile][$key])
) {
return null;
}

// INI_SCANNER_NORMAL parses false-y values as an empty string
if ($data[$profile][$key] === "") {
if ($expectedType === 'bool') {
$data[$profile][$key] = false;
} elseif ($expectedType === 'int') {
$data[$profile][$key] = 0;
}
}

return self::convertType($data[$profile][$key], $expectedType);
}

/**
* Gets the environment's HOME directory if available.
*
* @return null | string
*/
private static function getHomeDir()
{
// On Linux/Unix-like systems, use the HOME environment variable
if ($homeDir = getenv('HOME')) {
return $homeDir;
}

// Get the HOMEDRIVE and HOMEPATH values for Windows hosts
$homeDrive = getenv('HOMEDRIVE');
$homePath = getenv('HOMEPATH');

return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;
}

/**
* Gets default config file location from environment, falling back to aws
* default location
*
* @return string
*/
private static function getDefaultConfigFilename()
{
if ($filename = getenv(self::ENV_CONFIG_FILE)) {
return $filename;
}
return self::getHomeDir() . '/.aws/config';
}

/**
* Normalizes string values pulled out of ini files and
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
* environment variables.
*
* @param string $value The value retrieved from the environment or
* ini file.
* @param $type $string The type that the value needs to be converted to.
*
* @return mixed
*/
private static function convertType($value, $type)
{
if ($type === 'bool'
&& !is_null($convertedValue = \Aws\boolean_value($value))
) {
return $convertedValue;
}

if ($type === 'int'
&& filter_var($value, FILTER_VALIDATE_INT)
) {
$value = intVal($value);
}
return $value;
}
}
1 change: 0 additions & 1 deletion src/Endpoint/UseFipsEndpoint/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
namespace Aws\Endpoint\UseFipsEndpoint;

use Aws;
use Aws\ClientResolver;
use Aws\Endpoint\UseFipsEndpoint\Exception\ConfigurationException;

class Configuration implements ConfigurationInterface
Expand Down
Loading