Skip to content

Commit

Permalink
feat: add AppID user agent parameter (#2917)
Browse files Browse the repository at this point in the history
Co-authored-by: Sean O'Brien <60306702+stobrien89@users.noreply.github.com>
  • Loading branch information
yenfryherrerafeliz and stobrien89 committed May 15, 2024
1 parent bc30df5 commit 9b6ef49
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 9 deletions.
7 changes: 7 additions & 0 deletions .changes/nextrelease/fix-user-agent-header.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"type": "feature",
"category": "User-Agent",
"description": "Update user agent implementation for supporting AppId and user agent version"
}
]
7 changes: 7 additions & 0 deletions src/AwsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@ public static function getArguments()
* client-side parameter validation.
* - version: (string, required) The version of the webservice to
* utilize (e.g., 2006-03-01).
* - ua_append: (string, array) To pass custom user agent parameters.
* - app_id: (string) an optional application specific identifier that can be set.
* When set it will be appended to the User-Agent header of every request
* in the form of App/{AppId}. This variable is sourced from environment
* variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
* See https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html for
* more information on environment variables and shared config settings.
*
* @param array $args Client configuration arguments.
*
Expand Down
59 changes: 50 additions & 9 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,15 @@ class ClientResolver
'fn' => [__CLASS__, '_apply_handler'],
'default' => [__CLASS__, '_default_handler']
],
'app_id' => [
'type' => 'value',
'valid' => ['string'],
'doc' => 'app_id(AppId) is an optional application specific identifier that can be set.
When set it will be appended to the User-Agent header of every request in the form of App/{AppId}.
This value is also sourced from environment variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.',
'fn' => [__CLASS__, '_apply_app_id'],
'default' => [__CLASS__, '_default_app_id']
],
'ua_append' => [
'type' => 'value',
'valid' => ['string', 'array'],
Expand Down Expand Up @@ -917,17 +926,43 @@ public static function _apply_http_handler($value, array &$args, HandlerList $li
);
}

public static function _apply_app_id($value, array &$args)
{
// AppId should not be longer than 50 chars
static $MAX_APP_ID_LENGTH = 50;
if (strlen($value) > $MAX_APP_ID_LENGTH) {
trigger_error("The provided or configured value for `AppId`, "
."which is an user agent parameter, exceeds the maximum length of "
."$MAX_APP_ID_LENGTH characters.", E_USER_WARNING);
}

$args['app_id'] = $value;
}

public static function _default_app_id(array $args)
{
return ConfigurationResolver::resolve(
'sdk_ua_app_id',
'',
'string',
$args
);
}

public static function _apply_user_agent($inputUserAgent, array &$args, HandlerList $list)
{
//Add SDK version
// Add SDK version
$userAgent = ['aws-sdk-php/' . Sdk::VERSION];

//If on HHVM add the HHVM version
// User Agent Metadata
$userAgent[] = 'ua/2.0';

// If on HHVM add the HHVM version
if (defined('HHVM_VERSION')) {
$userAgent []= 'HHVM/' . HHVM_VERSION;
}

//Add OS version
// Add OS version
$disabledFunctions = explode(',', ini_get('disable_functions'));
if (function_exists('php_uname')
&& !in_array('php_uname', $disabledFunctions, true)
Expand All @@ -938,15 +973,15 @@ public static function _apply_user_agent($inputUserAgent, array &$args, HandlerL
}
}

//Add the language version
// Add the language version
$userAgent []= 'lang/php#' . phpversion();

//Add exec environment if present
// Add exec environment if present
if ($executionEnvironment = getenv('AWS_EXECUTION_ENV')) {
$userAgent []= $executionEnvironment;
}

//Add endpoint discovery if set
// Add endpoint discovery if set
if (isset($args['endpoint_discovery'])) {
if (($args['endpoint_discovery'] instanceof \Aws\EndpointDiscovery\Configuration
&& $args['endpoint_discovery']->isEnabled())
Expand All @@ -960,7 +995,7 @@ public static function _apply_user_agent($inputUserAgent, array &$args, HandlerL
}
}

//Add retry mode if set
// Add retry mode if set
if (isset($args['retries'])) {
if ($args['retries'] instanceof \Aws\Retry\Configuration) {
$userAgent []= 'cfg/retry-mode#' . $args["retries"]->getMode();
Expand All @@ -970,7 +1005,13 @@ public static function _apply_user_agent($inputUserAgent, array &$args, HandlerL
$userAgent []= 'cfg/retry-mode#' . $args["retries"]["mode"];
}
}
//Add the input to the end

// AppID Metadata
if (!empty($args['app_id'])) {
$userAgent[] = 'app/' . $args['app_id'];
}

// Add the input to the end
if ($inputUserAgent){
if (!is_array($inputUserAgent)) {
$inputUserAgent = [$inputUserAgent];
Expand Down Expand Up @@ -1188,7 +1229,7 @@ public static function _default_endpoint(array &$args)

return $value;
}

public static function _apply_region($value, array &$args)
{
if (empty($value)) {
Expand Down
86 changes: 86 additions & 0 deletions tests/ClientResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Aws\HandlerList;
use Aws\Sdk;
use Aws\Result;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\RequestInterface;
use Yoast\PHPUnitPolyfills\TestCases\TestCase;

Expand Down Expand Up @@ -1574,4 +1575,89 @@ public function testIgnoreConfiguredEndpointUrls()
putenv('AWS_ENDPOINT_URL' . '=');
putenv('AWS_ENDPOINT_URL_S3' . '=');
}

public function testResolvesAppIdFromClientConfig()
{
$appId = 'TestAppId';
$s3 = new S3Client([
'region' => 'us-east-1',
'app_id' => $appId,
'http_handler' => function (RequestInterface $request) use ($appId) {
$userAgentValues = explode(' ', $request->getHeader('user-agent')[0]);
$expectedHeader = "app/$appId";
$idx = array_search($expectedHeader, $userAgentValues);
$this->assertNotFalse($idx);
$this->assertEquals($expectedHeader, $userAgentValues[$idx]);

return new Response;
}
]);
$s3->listBuckets();
}

public function testResolvesAppIdSourcedFromEnv()
{
$currentAppIdFromEnv = getenv('AWS_SDK_UA_APP_ID');
$deferTask = function () use ($currentAppIdFromEnv) {
if (!empty($currentAppIdFromEnv)) {
putenv("AWS_SDK_UA_APP_ID=$currentAppIdFromEnv");
}
};

try {
$appId = 'TestAppId';
putenv("AWS_SDK_UA_APP_ID=$appId");
$s3 = new S3Client([
'region' => 'us-east-1',
'http_handler' => function (RequestInterface $request) use ($appId) {
$userAgentValues = explode(' ', $request->getHeader('user-agent')[0]);
$expectedHeader = "app/$appId";
$idx = array_search($expectedHeader, $userAgentValues);
$this->assertNotFalse($idx);
$this->assertEquals($expectedHeader, $userAgentValues[$idx]);

return new Response;
}
]);
$s3->listBuckets();
} finally {
$deferTask();
}
}

public function testResolvesAppIdSourcedFromIniFile()
{
$tempIniConfigFile = sys_get_temp_dir() . '/.aws/config';
$currentAwsConfigFileFromEnv = getenv('AWS_CONFIG_FILE');
$deferTask = function () use ($tempIniConfigFile, $currentAwsConfigFileFromEnv) {
unlink($tempIniConfigFile);
if (!empty($currentAwsConfigFileFromEnv)) {
putenv("AWS_CONFIG_FILE=$currentAwsConfigFileFromEnv");
}
};
$appId = 'TestAppId';
$iniContent = <<<EOF
[default]
sdk_ua_app_id=$appId
EOF;
file_put_contents($tempIniConfigFile, $iniContent);
putenv("AWS_CONFIG_FILE=$tempIniConfigFile");
try {
$s3 = new S3Client([
'region' => 'us-east-1',
'http_handler' => function (RequestInterface $request) use ($appId) {
$userAgentValues = explode(' ', $request->getHeader('user-agent')[0]);
$expectedHeader = "app/$appId";
$idx = array_search($expectedHeader, $userAgentValues);
$this->assertNotFalse($idx);
$this->assertEquals($expectedHeader, $userAgentValues[$idx]);

return new Response;
}
]);
$s3->listBuckets();
} finally {
$deferTask();
}
}
}

0 comments on commit 9b6ef49

Please sign in to comment.