Skip to content

Commit

Permalink
Merge pull request aws#708 from jeskew/feature/configurable-user-agent
Browse files Browse the repository at this point in the history
Allow user-defined user agents
  • Loading branch information
jeskew committed Jul 31, 2015
2 parents ff3a8b1 + d51162c commit b34b8a5
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 3 deletions.
10 changes: 10 additions & 0 deletions docs/guide/configuration.rst
Expand Up @@ -722,6 +722,16 @@ The following examples show how to configure an Amazon S3 client to use
signature versions.


ua_append
~~~~~~~~~

:Type: ``string|string[]``
:Default: ``[]``

A string or array of strings that will be added to the user-agent string passed
to the HTTP handler.


validate
~~~~~~~~

Expand Down
37 changes: 36 additions & 1 deletion src/ClientResolver.php
Expand Up @@ -11,6 +11,7 @@
use Aws\Credentials\CredentialProvider;
use GuzzleHttp\Promise;
use InvalidArgumentException as IAE;
use Psr\Http\Message\RequestInterface;

/**
* @internal Resolves a hash of client arguments to construct a client.
Expand Down Expand Up @@ -146,7 +147,14 @@ class ClientResolver
'doc' => 'A handler that accepts a command object, request object and returns a promise that is fulfilled with an Aws\ResultInterface object or rejected with an Aws\Exception\AwsException. A handler does not accept a next handler as it is terminal and expected to fulfill a command. If no handler is provided, a default Guzzle handler will be utilized.',
'fn' => [__CLASS__, '_apply_handler'],
'default' => [__CLASS__, '_default_handler']
]
],
'ua_append' => [
'type' => 'value',
'valid' => ['string', 'array'],
'doc' => 'Provide a string or array of strings to send in the User-Agent header.',
'fn' => [__CLASS__, '_apply_user_agent'],
'default' => [],
],
];

/**
Expand Down Expand Up @@ -441,6 +449,33 @@ public static function _apply_http_handler($value, array &$args, HandlerList $li
);
}

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

$value = array_map('strval', $value);

array_unshift($value, 'aws-sdk-php/' . Sdk::VERSION);
$args['ua_append'] = $value;

$list->appendBuild(static function (callable $handler) use ($value) {
return function (
CommandInterface $command,
RequestInterface $request
) use ($handler, $value) {
return $handler($command, $request->withHeader(
'User-Agent',
implode(' ', array_merge(
$value,
$request->getHeader('User-Agent')
))
));
};
});
}

public static function _default_endpoint_provider()
{
return EndpointProvider::defaultProvider();
Expand Down
4 changes: 3 additions & 1 deletion src/Handler/GuzzleV5/GuzzleHandler.php
Expand Up @@ -129,9 +129,11 @@ private function createGuzzleRequest(Psr7Request $psrRequest, array $options)
}

$request->setHeaders($psrRequest->getHeaders());

$request->setHeader(
'User-Agent',
'aws-sdk-php/' . Sdk::VERSION . ' ' . Client::getDefaultUserAgent()
$request->getHeader('User-Agent')
. ' ' . Client::getDefaultUserAgent()
);

// Make sure the delay is configured, if provided.
Expand Down
3 changes: 2 additions & 1 deletion src/Handler/GuzzleV6/GuzzleHandler.php
Expand Up @@ -36,7 +36,8 @@ public function __invoke(Psr7Request $request, array $options = [])
{
$request = $request->withHeader(
'User-Agent',
'aws-sdk-php/' . Sdk::VERSION . ' ' . \GuzzleHttp\default_user_agent()
$request->getHeaderLine('User-Agent')
. ' ' . \GuzzleHttp\default_user_agent()
);

return $this->client->sendAsync($request, $options)->otherwise(
Expand Down
44 changes: 44 additions & 0 deletions tests/ClientResolverTest.php
Expand Up @@ -2,13 +2,16 @@
namespace Aws\Test;

use Aws\ClientResolver;
use Aws\CommandInterface;
use Aws\Credentials\CredentialProvider;
use Aws\Credentials\Credentials;
use Aws\DynamoDb\DynamoDbClient;
use Aws\S3\S3Client;
use Aws\HandlerList;
use Aws\Sdk;
use Aws\WrappedHttpHandler;
use GuzzleHttp\Promise\RejectedPromise;
use Psr\Http\Message\RequestInterface;

/**
* @covers Aws\ClientResolver
Expand Down Expand Up @@ -382,4 +385,45 @@ public function testAddsTraceMiddleware()
$value = $this->readAttribute($list, 'interposeFn');
$this->assertTrue(is_callable($value));
}

public function testAppliesUserAgent()
{
$r = new ClientResolver(ClientResolver::getDefaultArguments());
$list = new HandlerList();
$conf = $r->resolve([
'service' => 'sqs',
'region' => 'x',
'credentials' => ['key' => 'a', 'secret' => 'b'],
'version' => 'latest',
'ua_append' => 'PHPUnit/Unit',
], $list);
$this->assertArrayHasKey('ua_append', $conf);
$this->assertInternalType('array', $conf['ua_append']);
$this->assertContains('PHPUnit/Unit', $conf['ua_append']);
$this->assertContains('aws-sdk-php/' . Sdk::VERSION, $conf['ua_append']);
}

public function testUserAgentAlwaysStartsWithSdkAgentString()
{
$command = $this->getMockBuilder(CommandInterface::class)
->disableOriginalConstructor()
->getMock();
$request = $this->getMockBuilder(RequestInterface::class)
->disableOriginalConstructor()
->getMock();

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

$request->expects($this->once())
->method('withHeader')
->with('User-Agent', 'aws-sdk-php/' . Sdk::VERSION . ' MockBuilder');

$args = [];
$list = new HandlerList(function () {});
ClientResolver::_apply_user_agent([], $args, $list);
call_user_func($list->resolve(), $command, $request);
}
}
1 change: 1 addition & 0 deletions tests/Integ/IntegUtils.php
Expand Up @@ -9,6 +9,7 @@ private static function getSdk(array $args = [])
'region' => 'us-east-1',
'profile' => 'integ',
'version' => 'latest',
'ua_append' => 'PHPUnit/Integration'
]);
}

Expand Down

0 comments on commit b34b8a5

Please sign in to comment.