PresignUrlMiddleware.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <?php
  2. namespace Aws;
  3. use Aws\AwsClientInterface;
  4. use Aws\Signature\SignatureV4;
  5. use Aws\Endpoint\EndpointProvider;
  6. use Aws\CommandInterface;
  7. use GuzzleHttp\Psr7\Uri;
  8. use Psr\Http\Message\RequestInterface;
  9. /**
  10. * @internal Adds computed values to service operations that need presigned url.
  11. */
  12. class PresignUrlMiddleware
  13. {
  14. private $client;
  15. private $endpointProvider;
  16. private $nextHandler;
  17. /** @var array names of operations that require presign url */
  18. private $commandPool;
  19. /** @var string */
  20. private $serviceName;
  21. /** @var string */
  22. private $presignParam;
  23. public function __construct(
  24. array $options,
  25. callable $endpointProvider,
  26. AwsClientInterface $client,
  27. callable $nextHandler
  28. ) {
  29. $this->endpointProvider = $endpointProvider;
  30. $this->client = $client;
  31. $this->nextHandler = $nextHandler;
  32. $this->commandPool = $options['operations'];
  33. $this->serviceName = $options['service'];
  34. $this->presignParam = $options['presign_param'];
  35. }
  36. public static function wrap(
  37. AwsClientInterface $client,
  38. callable $endpointProvider,
  39. array $options = []
  40. ) {
  41. return function (callable $handler) use ($endpointProvider, $client, $options) {
  42. $f = new PreSignUrlMiddleware($options, $endpointProvider, $client, $handler);
  43. return $f;
  44. };
  45. }
  46. public function __invoke(CommandInterface $cmd, RequestInterface $request = null)
  47. {
  48. if (in_array($cmd->getName(), $this->commandPool)
  49. && (!isset($cmd->{'__skip' . $cmd->getName()}))
  50. ) {
  51. $cmd[$this->presignParam] = $this->createPresignedUrl($this->client, $cmd);
  52. $cmd['DestinationRegion'] = $this->client->getRegion();
  53. }
  54. $f = $this->nextHandler;
  55. return $f($cmd, $request);
  56. }
  57. private function createPresignedUrl(
  58. AwsClientInterface $client,
  59. CommandInterface $cmd
  60. ) {
  61. $cmdName = $cmd->getName();
  62. $newCmd = $client->getCommand($cmdName, $cmd->toArray());
  63. // Avoid infinite recursion by flagging the new command.
  64. $newCmd->{'__skip' . $cmdName} = true;
  65. // Serialize a request for the operation.
  66. $request = \Aws\serialize($newCmd);
  67. // Create the new endpoint for the target endpoint.
  68. $endpoint = EndpointProvider::resolve($this->endpointProvider, [
  69. 'region' => $cmd['SourceRegion'],
  70. 'service' => $this->serviceName,
  71. ])['endpoint'];
  72. // Set the request to hit the target endpoint.
  73. $uri = $request->getUri()->withHost((new Uri($endpoint))->getHost());
  74. $request = $request->withUri($uri);
  75. // Create a presigned URL for our generated request.
  76. $signer = new SignatureV4($this->serviceName, $cmd['SourceRegion']);
  77. return (string) $signer->presign(
  78. SignatureV4::convertPostToGet($request),
  79. $client->getCredentials()->wait(),
  80. '+1 hour'
  81. )->getUri();
  82. }
  83. }