diff --git a/Storage/src/StorageObject.php b/Storage/src/StorageObject.php index e4cdc69442c7..2298c9daad73 100644 --- a/Storage/src/StorageObject.php +++ b/Storage/src/StorageObject.php @@ -874,6 +874,12 @@ public function signedUrl($expires, array $options = []) } $options['cname'] = trim($options['cname'], '/'); + + // If a custom cname is used, then the resource is simply the objectName + if ($options['cname'] !== self::DEFAULT_DOWNLOAD_URL) { + $resource = '/' . $objectName; + } + return $options['cname'] . $resource . '?' . implode('&', $query); } diff --git a/Storage/tests/Unit/StorageObjectTest.php b/Storage/tests/Unit/StorageObjectTest.php index 3ae8ab842c48..e03d8b7cf41d 100644 --- a/Storage/tests/Unit/StorageObjectTest.php +++ b/Storage/tests/Unit/StorageObjectTest.php @@ -1024,6 +1024,41 @@ public function testSignedUrlInvalidKeyFileMissingClientEmail() ]); } + /** + * @group storage-signed-url + */ + public function testSignedUrlCname() + { + $object = new StorageObjectSignatureStub($this->connection->reveal(), self::OBJECT, self::BUCKET); + $ts = new Timestamp(new \DateTime(self::TIMESTAMP)); + + $seconds = $ts->get()->format('U'); + + $url = $object->signedUrl($ts, [ + 'keyFile' => $this->kf, + 'cname' => 'https://cdn.example.com', + ]); + + $input = implode("\n", [ + 'GET', + '', + '', + $seconds, + '/bucket/object.txt' + ]); + + $parts = explode('?', $url); + $hostPath = $parts[0]; + $query = $parts[1]; + $pieces = explode('&', $query); + + $signature = $this->getSignatureFromSplitUrl($pieces); + + $this->assertTrue($object->___signatureIsCorrect($signature)); + $this->assertEquals($object->input, $input); + $this->assertEquals('https://cdn.example.com/object.txt', $hostPath); + } + public function testRequesterPays() { $this->connection->getObject(Argument::withEntry('userProject', 'foo'))