-
Notifications
You must be signed in to change notification settings - Fork 380
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #318 from digitalkaoz/s3_proxy_cache
added proxy cache resolver
- Loading branch information
Showing
4 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
|
||
namespace Liip\ImagineBundle\Imagine\Cache\Resolver; | ||
|
||
use Symfony\Component\HttpFoundation\RedirectResponse; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpKernel\Kernel; | ||
|
||
/** | ||
* ProxyResolver | ||
* | ||
* @author Robert Schönthal <robert.schoenthal@gmail.com> | ||
*/ | ||
class ProxyResolver implements ResolverInterface | ||
{ | ||
/** | ||
* @var ResolverInterface | ||
*/ | ||
private $resolver; | ||
|
||
/** | ||
* a list of proxy hosts (picks a random one for each generation to seed browser requests among multiple hosts) | ||
* | ||
* @var array | ||
*/ | ||
private $hosts = array(); | ||
|
||
/** | ||
* @param ResolverInterface $resolver | ||
*/ | ||
public function __construct(ResolverInterface $resolver, array $hosts) | ||
{ | ||
$this->resolver = $resolver; | ||
$this->hosts = $hosts; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function resolve(Request $request, $path, $filter) | ||
{ | ||
$response = $this->resolver->resolve($request, $path, $filter); | ||
$this->rewriteResponse($response); | ||
|
||
return $response; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function store(Response $response, $targetPath, $filter) | ||
{ | ||
$response = $this->resolver->store($response, $targetPath, $filter); | ||
$this->rewriteResponse($response); | ||
|
||
return $response; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getBrowserPath($path, $filter, $absolute = false) | ||
{ | ||
$response = $this->resolver->getBrowserPath($path, $filter, $absolute); | ||
$this->rewriteResponse($response); | ||
|
||
return $response; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function remove($targetPath, $filter) | ||
{ | ||
return $this->resolver->remove($targetPath, $filter); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function clear($cachePrefix) | ||
{ | ||
$this->resolver->clear($cachePrefix); | ||
} | ||
|
||
private function rewriteResponse($response) | ||
{ | ||
if (!$response instanceof RedirectResponse || !$this->hosts) { | ||
return; | ||
} | ||
|
||
if ('2' == Kernel::MAJOR_VERSION && '0' == Kernel::MINOR_VERSION) { | ||
$redirectLocation = $response->headers->get('Location'); | ||
} else { | ||
$redirectLocation = $response->getTargetUrl(); | ||
} | ||
$path = parse_url($redirectLocation, PHP_URL_PATH); | ||
|
||
if ($path == $redirectLocation) { | ||
//relative path, so strip of SCRIPT_FILE_NAME if existient | ||
$path = substr($path, (strpos($path, '.php') !== false ? strpos($path, '.php') + 4 : 0)); | ||
} | ||
|
||
if ('2' == Kernel::MAJOR_VERSION && '0' == Kernel::MINOR_VERSION) { | ||
$response->headers->set('Location', $this->createProxyUrl($path)); | ||
} else { | ||
$response->setTargetUrl($this->createProxyUrl($path)); | ||
} | ||
} | ||
|
||
private function createProxyUrl($path) | ||
{ | ||
$domain = $this->hosts[rand(0, count($this->hosts) - 1)]; | ||
|
||
return $domain . $path; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# ProxyResolver | ||
|
||
The ProxyResolver is a `decorator` for every other Resolver | ||
|
||
This Resolver adds the possibility to use Proxy Hosts for your Assets. | ||
If no Proxy Domains are set, it behaves like the underlying `Resolver` | ||
|
||
## Set Proxy Domains | ||
|
||
In order to use this Resolver you must create a Service and inject some domains and your underlying Resolver | ||
|
||
``` yaml | ||
services: | ||
acme.imagine.cache.resolver.proxy: | ||
class: Liip\ImagineBundle\Imagine\Cache\Resolver\ProxyResolver | ||
arguments: | ||
- "@acme.imagine.cache.resolver.amazon_s3" | ||
- [ 'http://images0.domain.com', 'http://images1.domain.com','http://images2.domain.com' ] | ||
tags: | ||
- { name: 'liip_imagine.cache.resolver', resolver: 'proxy' } | ||
``` | ||
Now your Resolver would generate following Urls `http://images0.domain.com/thumbs/article_thumb/foo.jpg` instead of the original path from the underlying Resolver `bucket.s3.awsamazoncloud.com/thumbs/article_thumb/foo.jpg` for every relevant Action. | ||
|
||
- [Back to cache resolvers](../cache-resolvers.md) | ||
- [Back to the index](../index.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<?php | ||
|
||
|
||
namespace Liip\ImagineBundle\Tests\Imagine\Cache\Resolver; | ||
|
||
use Liip\ImagineBundle\Imagine\Cache\Resolver\ProxyResolver; | ||
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface; | ||
use Liip\ImagineBundle\Tests\AbstractTest; | ||
use Symfony\Component\HttpFoundation\RedirectResponse; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpKernel\Kernel; | ||
|
||
|
||
/** | ||
* ProxyResolverTest | ||
* | ||
* @author Robert Schönthal <robert.schoenthal@gmail.com> | ||
*/ | ||
class ProxyResolverTest extends AbstractTest | ||
{ | ||
/** | ||
* @var ResolverInterface | ||
*/ | ||
private $primaryResolver; | ||
|
||
/** | ||
* @var ProxyResolver | ||
*/ | ||
private $resolver; | ||
|
||
public function setUp() | ||
{ | ||
$this->primaryResolver = $this->getMock('Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface'); | ||
|
||
$this->resolver = new ProxyResolver($this->primaryResolver, array('http://images.example.com')); | ||
} | ||
|
||
public function testResolveWithResponse() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('resolve') | ||
->will($this->returnValue(new RedirectResponse('app_dev.php/thumbs/foo/bar/bazz.png'))); | ||
|
||
$result = $this->resolver->resolve(new Request(), '/foo/bar/bazz.png', 'test'); | ||
|
||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $result); | ||
|
||
if ('2' == Kernel::MAJOR_VERSION && '0' == Kernel::MINOR_VERSION) { | ||
$this->assertEquals('http://images.example.com/thumbs/foo/bar/bazz.png', $result->headers->get('Location')); | ||
} else { | ||
$this->assertEquals('http://images.example.com/thumbs/foo/bar/bazz.png', $result->getTargetUrl()); | ||
} | ||
} | ||
|
||
public function testResolveWithoutResponse() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('resolve') | ||
->will($this->returnValue('app_dev.php/thumbs/foo/bar/bazz.png')); | ||
|
||
$result = $this->resolver->resolve(new Request(), '/foo/bar/bazz.png', 'test'); | ||
|
||
$this->assertEquals('app_dev.php/thumbs/foo/bar/bazz.png', $result); | ||
} | ||
|
||
public function testStoreWithResponse() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('store') | ||
->will($this->returnValue(new RedirectResponse('http://foo.com/thumbs/foo/bar/bazz.png'))); | ||
|
||
$result = $this->resolver->store(new Response(), '/foo/bar/bazz.png', 'test'); | ||
|
||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $result); | ||
|
||
if ('2' == Kernel::MAJOR_VERSION && '0' == Kernel::MINOR_VERSION) { | ||
$this->assertEquals('http://images.example.com/thumbs/foo/bar/bazz.png', $result->headers->get('Location')); | ||
} else { | ||
$this->assertEquals('http://images.example.com/thumbs/foo/bar/bazz.png', $result->getTargetUrl()); | ||
} | ||
} | ||
|
||
public function testStoreWithoutResponse() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('store') | ||
->will($this->returnValue('http://foo.com/thumbs/foo/bar/bazz.png')); | ||
|
||
$result = $this->resolver->store(new Response(), '/foo/bar/bazz.png', 'test'); | ||
|
||
$this->assertEquals('http://foo.com/thumbs/foo/bar/bazz.png', $result); | ||
} | ||
|
||
public function testGetBrowserPathWithResponse() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('getBrowserPath') | ||
->will($this->returnValue(new RedirectResponse('s3://myfunkybucket/thumbs/foo/bar/bazz.png'))); | ||
|
||
$result = $this->resolver->getBrowserPath('/foo/bar/bazz.png', 'test'); | ||
|
||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $result); | ||
|
||
if ('2' == Kernel::MAJOR_VERSION && '0' == Kernel::MINOR_VERSION) { | ||
$this->assertEquals('http://images.example.com/thumbs/foo/bar/bazz.png', $result->headers->get('Location')); | ||
} else { | ||
$this->assertEquals('http://images.example.com/thumbs/foo/bar/bazz.png', $result->getTargetUrl()); | ||
} | ||
} | ||
|
||
public function testGetBrowserPathWithoutResponse() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('getBrowserPath') | ||
->will($this->returnValue('s3://myfunkybucket/thumbs/foo/bar/bazz.png')); | ||
|
||
$result = $this->resolver->getBrowserPath('/foo/bar/bazz.png', 'test'); | ||
|
||
$this->assertEquals('s3://myfunkybucket/thumbs/foo/bar/bazz.png', $result); | ||
} | ||
|
||
public function testRemove() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('remove'); | ||
|
||
$this->resolver->remove('/foo/bar/bazz.png', 'test'); | ||
} | ||
|
||
public function testClear() | ||
{ | ||
$this->primaryResolver | ||
->expects($this->once()) | ||
->method('clear'); | ||
|
||
$this->resolver->clear('test'); | ||
} | ||
|
||
} |