diff --git a/src/Illuminate/Http/Middleware/Cache.php b/src/Illuminate/Http/Middleware/Cache.php index e9beaf798329..9af851365656 100644 --- a/src/Illuminate/Http/Middleware/Cache.php +++ b/src/Illuminate/Http/Middleware/Cache.php @@ -11,39 +11,37 @@ class Cache * * @param \Illuminate\Http\Request $request * @param \Closure $next - * @param int|null $maxAge - * @param int|null $sharedMaxAge - * @param bool|null $public - * @param bool|null $etag + * @param string|array $options * @return \Symfony\Component\HttpFoundation\Response + * @throws \InvalidArgumentException */ - public function handle($request, Closure $next, int $maxAge = null, int $sharedMaxAge = null, bool $public = null, bool $etag = false) + public function handle($request, Closure $next, $options = []) { /** - * @var \Symfony\Component\HttpFoundation\Response + * @var $response \Symfony\Component\HttpFoundation\Response */ $response = $next($request); - if (! $request->isMethodCacheable() || ! $response->getContent()) { return $response; } - if (! $response->getContent()) { - return; - } - if ($etag) { - $response->setEtag(md5($response->getContent())); - } - if (null !== $maxAge) { - $response->setMaxAge($maxAge); - } - if (null !== $sharedMaxAge) { - $response->setSharedMaxAge($sharedMaxAge); + if (\is_string($options)) { + $parsedOptions = []; + foreach (explode(';', $options) as $opt) { + $data = explode('=', $opt, 2); + $parsedOptions[$data[0]] = $data[1] ?? true; + } + + $options = $parsedOptions; } - if (null !== $public) { - $public ? $response->setPublic() : $response->setPrivate(); + + if (true === ($options['etag'] ?? false)) { + $options['etag'] = md5($response->getContent()); } + $response->setCache($options); + $response->isNotModified($request); + return $response; } } diff --git a/tests/Http/Middleware/CacheTest.php b/tests/Http/Middleware/CacheTest.php index eb5268d75aac..6d865e973bdc 100644 --- a/tests/Http/Middleware/CacheTest.php +++ b/tests/Http/Middleware/CacheTest.php @@ -16,17 +16,16 @@ public function testDoNotSetHeaderWhenMethodNotCacheable() $response = (new Cache())->handle($request, function () { return new Response('Hello Laravel'); - }, 1, 2, true, true); + }, 'max_age=120;s_maxage=60'); $this->assertNull($response->getMaxAge()); - $this->assertNull($response->getEtag()); } public function testDoNotSetHeaderWhenNoContent() { $response = (new Cache())->handle(new Request(), function () { return new Response(); - }, 1, 2, true, true); + }, 'max_age=120;s_maxage=60'); $this->assertNull($response->getMaxAge()); $this->assertNull($response->getEtag()); @@ -36,9 +35,51 @@ public function testAddHeaders() { $response = (new Cache())->handle(new Request(), function () { return new Response('some content'); - }, 100, 200, true, true); + }, 'max_age=100;s_maxage=200;etag=ABC'); + + $this->assertSame('"ABC"', $response->getEtag()); + $this->assertSame('max-age=100, public, s-maxage=200', $response->headers->get('Cache-Control')); + } + + public function testAddHeadersUsingArray() + { + $response = (new Cache())->handle(new Request(), function () { + return new Response('some content'); + }, ['max_age' => 100, 's_maxage' => 200, 'etag' => 'ABC']); + + $this->assertSame('"ABC"', $response->getEtag()); + $this->assertSame('max-age=100, public, s-maxage=200', $response->headers->get('Cache-Control')); + } + + public function testGenerateEtag() + { + $response = (new Cache())->handle(new Request(), function () { + return new Response('some content'); + }, 'etag;max_age=100;s_maxage=200'); $this->assertSame('"9893532233caff98cd083a116b013c0b"', $response->getEtag()); $this->assertSame('max-age=100, public, s-maxage=200', $response->headers->get('Cache-Control')); } + + public function testIsNotModified() + { + $request = new Request(); + $request->headers->set('If-None-Match', '"9893532233caff98cd083a116b013c0b"'); + + $response = (new Cache())->handle($request, function () { + return new Response('some content'); + }, 'etag;max_age=100;s_maxage=200'); + + $this->assertSame(304, $response->getStatusCode()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidOption() + { + (new Cache())->handle(new Request(), function () { + return new Response('some content'); + }, 'invalid'); + } }