Skip to content
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: 7 additions & 0 deletions .changes/nextrelease/feature-user-agent-v2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"type": "feature",
"category": "",
"description": "User agent header updated to include info on OS and language version"
}
]
72 changes: 51 additions & 21 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -668,44 +668,74 @@ public static function _apply_http_handler($value, array &$args, HandlerList $li
);
}

public static function _apply_user_agent($value, array &$args, HandlerList $list)
public static function _apply_user_agent($inputUserAgent, array &$args, HandlerList $list)
{
if (!is_array($value)) {
$value = [$value];
}

$value = array_map('strval', $value);
//Add SDK version
$xAmzUserAgent = ['aws-sdk-php/' . Sdk::VERSION];

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

//Set up the updated user agent
$legacyUserAgent = $xAmzUserAgent;

//Add OS version
$disabledFunctions = explode(',', ini_get('disable_functions'));
if (!ini_get('safe_mode')
&& function_exists('php_uname')
if (function_exists('php_uname')
&& !in_array('php_uname', $disabledFunctions, true)
) {
$osName = "OS/" . php_uname('s') . '/' . php_uname('r');
if (!empty($osName)) {
array_unshift($value, $osName);
$legacyUserAgent []= $osName;
}
}

array_unshift($value, 'aws-sdk-php/' . Sdk::VERSION);
$args['ua_append'] = $value;
//Add the language version
$legacyUserAgent []= 'lang/php/' . phpversion();

$list->appendBuild(static function (callable $handler) use ($value) {
//Add exec environment if present
if ($executionEnvironment = getenv('AWS_EXECUTION_ENV')) {
$legacyUserAgent []= $executionEnvironment;
}

//Add the input to the end
if ($inputUserAgent){
if (!is_array($inputUserAgent)) {
$inputUserAgent = [$inputUserAgent];
}
$inputUserAgent = array_map('strval', $inputUserAgent);
$legacyUserAgent = array_merge($legacyUserAgent, $inputUserAgent);
$xAmzUserAgent = array_merge($xAmzUserAgent, $inputUserAgent);
}

$args['ua_append'] = $legacyUserAgent;

$list->appendBuild(static function (callable $handler) use (
$xAmzUserAgent,
$legacyUserAgent
) {
return function (
CommandInterface $command,
RequestInterface $request
) use ($handler, $value) {
return $handler($command, $request->withHeader(
'User-Agent',
implode(' ', array_merge(
$value,
$request->getHeader('User-Agent')
))
));
) use ($handler, $legacyUserAgent, $xAmzUserAgent) {
return $handler(
$command,
$request->withHeader(
'X-Amz-User-Agent',
implode(' ', array_merge(
$xAmzUserAgent,
$request->getHeader('X-Amz-User-Agent')
))
)->withHeader(
'User-Agent',
implode(' ', array_merge(
$legacyUserAgent,
$request->getHeader('User-Agent')
))
)
);
};
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/S3/Crypto/S3EncryptionClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public function __construct(
S3Client $client,
$instructionFileSuffix = null
) {
$this->appendUserAgent($client, 'S3CryptoV' . self::CRYPTO_VERSION);
$this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
$this->client = $client;
$this->instructionFileSuffix = $instructionFileSuffix;
}
Expand Down
2 changes: 1 addition & 1 deletion src/S3/Crypto/S3EncryptionClientV2.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function __construct(
S3Client $client,
$instructionFileSuffix = null
) {
$this->appendUserAgent($client, 'S3CryptoV' . self::CRYPTO_VERSION);
$this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
$this->client = $client;
$this->instructionFileSuffix = $instructionFileSuffix;
$this->legacyWarningCount = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/S3/Crypto/S3EncryptionMultipartUploader.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public function __construct(
$source,
array $config = []
) {
$this->appendUserAgent($client, 'S3CryptoV' . self::CRYPTO_VERSION);
$this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
$this->client = $client;
$config['params'] = [];
if (!empty($config['bucket'])) {
Expand Down
2 changes: 1 addition & 1 deletion src/S3/Crypto/S3EncryptionMultipartUploaderV2.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public function __construct(
$source,
array $config = []
) {
$this->appendUserAgent($client, 'S3CryptoV' . self::CRYPTO_VERSION);
$this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
$this->client = $client;
$config['params'] = [];
if (!empty($config['bucket'])) {
Expand Down
4 changes: 4 additions & 0 deletions src/Signature/SignatureV4.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ private function getHeaderBlacklist()
'from' => true,
'referer' => true,
'user-agent' => true,
'X-Amz-User-Agent' => true,
'x-amzn-trace-id' => true,
'aws-sdk-invocation-id' => true,
'aws-sdk-retry' => true,
Expand Down Expand Up @@ -364,6 +365,9 @@ private function convertExpires($expiresTimestamp, $startTimestamp)

private function moveHeadersToQuery(array $parsedRequest)
{
//x-amz-user-agent shouldn't be put in a query param
unset($parsedRequest['headers']['X-Amz-User-Agent']);

foreach ($parsedRequest['headers'] as $name => $header) {
$lname = strtolower($name);
if (substr($lname, 0, 5) == 'x-amz') {
Expand Down
21 changes: 18 additions & 3 deletions tests/ClientResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -715,26 +715,41 @@ public function testUserAgentAlwaysStartsWithSdkAgentString()
->disableOriginalConstructor()
->getMock();

$request->expects($this->once())
$request->expects($this->at(0))
->method('getHeader')
->with('X-Amz-User-Agent')
->willReturn(["MockBuilder"]);

$request->expects($this->at(1))
->method('withHeader')
->with(
'X-Amz-User-Agent',
new \PHPUnit\Framework\Constraint\RegularExpression(
'/aws-sdk-php\/' . Sdk::VERSION . '.* MockBuilder/'
)
)->willReturn($request);

$request->expects($this->at(2))
->method('getHeader')
->with('User-Agent')
->willReturn(['MockBuilder']);

$request->expects($this->once())
$request->expects($this->at(3))
->method('withHeader')
->with(
'User-Agent',
new \PHPUnit\Framework\Constraint\RegularExpression(
'/aws-sdk-php\/' . Sdk::VERSION . '.* MockBuilder/'
)
);
)->willReturn($request);

$args = [];
$list = new HandlerList(function () {});
ClientResolver::_apply_user_agent([], $args, $list);
call_user_func($list->resolve(), $command, $request);
}


/**
* @dataProvider statValueProvider
* @param bool|array $userValue
Expand Down
2 changes: 1 addition & 1 deletion tests/S3/Crypto/S3EncryptionClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ public function testAddsCryptoUserAgent()
'version' => 'latest',
'http_handler' => function (RequestInterface $req) use ($provider) {
$this->assertContains(
'S3CryptoV' . S3EncryptionClient::CRYPTO_VERSION,
'feat/s3-encrypt/' . S3EncryptionClient::CRYPTO_VERSION,
$req->getHeaderLine('User-Agent')
);
return Promise\promise_for(new Response(
Expand Down
2 changes: 1 addition & 1 deletion tests/S3/Crypto/S3EncryptionClientV2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ public function testAddsCryptoUserAgent()
'version' => 'latest',
'http_handler' => function (RequestInterface $req) use ($provider) {
$this->assertContains(
'S3CryptoV' . S3EncryptionClientV2::CRYPTO_VERSION,
'feat/s3-encrypt/' . S3EncryptionClientV2::CRYPTO_VERSION,
$req->getHeaderLine('User-Agent')
);
return Promise\promise_for(new Response(
Expand Down
2 changes: 1 addition & 1 deletion tests/S3/Crypto/S3EncryptionMultipartUploaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ public function testAddsCryptoUserAgent()
$list = $s3->getHandlerList();
$list->appendSign(Middleware::tap(function($cmd, $req) {
$this->assertContains(
'S3CryptoV' . S3EncryptionMultipartUploader::CRYPTO_VERSION,
'feat/s3-encrypt/' . S3EncryptionMultipartUploader::CRYPTO_VERSION,
$req->getHeaderLine('User-Agent')
);
}));
Expand Down
2 changes: 1 addition & 1 deletion tests/S3/Crypto/S3EncryptionMultipartUploaderV2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ public function testAddsCryptoUserAgent()
$list = $s3->getHandlerList();
$list->appendSign(Middleware::tap(function($cmd, $req) {
$this->assertContains(
'S3CryptoV' . S3EncryptionMultipartUploaderV2::CRYPTO_VERSION,
'feat/s3-encrypt/' . S3EncryptionMultipartUploaderV2::CRYPTO_VERSION,
$req->getHeaderLine('User-Agent')
);
}));
Expand Down
1 change: 1 addition & 0 deletions tests/Signature/SignatureV4Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ public function testPresignBlacklistedHeaders()
]);
$presigned = $sig->presign($req, $creds, '+5 minutes');
$this->assertNotContains('user-agent', (string)$presigned->getUri());
$this->assertNotContains('X-Amz-User-Agent', (string)$presigned->getUri());
$this->assertNotContains('content-length', (string)$presigned->getUri());
$this->assertNotContains('Content-Type', (string)$presigned->getUri());
}
Expand Down