From 621063bca9ebc452eb84b511f258557ffc3e5da4 Mon Sep 17 00:00:00 2001 From: Jeroen Noten Date: Tue, 5 Aug 2014 20:37:37 +0200 Subject: [PATCH] added comments --- .../LaravelPrerenderServiceProvider.php | 13 +-- .../LaravelPrerender/PrerenderMiddleware.php | 84 +++++++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/Nutsweb/LaravelPrerender/LaravelPrerenderServiceProvider.php b/src/Nutsweb/LaravelPrerender/LaravelPrerenderServiceProvider.php index 8d4e787..0e501f0 100644 --- a/src/Nutsweb/LaravelPrerender/LaravelPrerenderServiceProvider.php +++ b/src/Nutsweb/LaravelPrerender/LaravelPrerenderServiceProvider.php @@ -1,7 +1,6 @@ getPackageNamespace($this->package, null); $config = $this->guessPackagePath() . '/config'; $this->app['config']->package($this->package, $config, $namespace); @@ -54,14 +55,4 @@ public function register() } } - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return array(); - } - } diff --git a/src/Nutsweb/LaravelPrerender/PrerenderMiddleware.php b/src/Nutsweb/LaravelPrerender/PrerenderMiddleware.php index c6b6ae2..7c57d65 100644 --- a/src/Nutsweb/LaravelPrerender/PrerenderMiddleware.php +++ b/src/Nutsweb/LaravelPrerender/PrerenderMiddleware.php @@ -13,18 +13,59 @@ class PrerenderMiddleware implements HttpKernelInterface { + /** + * The application instance (implements the HttpKernelInterface) + * + * @var HttpKernelInterface + */ private $app; + /** + * The Guzzle Client that sends GET requests to the prerender server + * This client must take care of the base URL by itself + * + * @var GuzzleClient + */ private $client; + /** + * This token will be provided via the X-Prerender-Token header. + * + * @var string + */ private $prerenderToken; + /** + * List of crawler user agents that will be + * + * @var array + */ private $crawlerUserAgents; + /** + * URI whitelist for prerendering pages only on this list + * + * @var array + */ private $whitelist; + /** + * URI blacklist for prerendering pages that are not on the list + * + * @var array + */ private $blacklist; + /** + * Creates a new PrerenderMiddleware instance + * + * @param HttpKernelInterface $app + * @param GuzzleClient $client + * @param $prerenderToken + * @param array $crawlerUserAgents + * @param array $whitelist + * @param array $blacklist + */ public function __construct(HttpKernelInterface $app, GuzzleClient $client, $prerenderToken, @@ -40,6 +81,14 @@ public function __construct(HttpKernelInterface $app, $this->blacklist = $blacklist; } + /** + * Handles a request and prerender if it should, otherwise call the next middleware. + * + * @param SymfonyRequest $request + * @param int $type + * @param bool $catch + * @return SymfonyResponse + */ public function handle(SymfonyRequest $request, $type = self::MASTER_REQUEST, $catch = true) { if ($this->shouldShowPrerenderedPage($request)) { @@ -52,6 +101,12 @@ public function handle(SymfonyRequest $request, $type = self::MASTER_REQUEST, $c return $this->app->handle($request, $type, $catch); } + /** + * Returns whether the request must be prerendered. + * + * @param SymfonyRequest $request + * @return bool + */ private function shouldShowPrerenderedPage(SymfonyRequest $request) { $userAgent = strtolower($request->server->get('HTTP_USER_AGENT')); @@ -64,8 +119,10 @@ private function shouldShowPrerenderedPage(SymfonyRequest $request) if (!$userAgent) return false; if (!$request->isMethod('GET')) return false; + // prerender if _escaped_fragment_ is in the query string if ($request->query->has('_escaped_fragment_')) $isRequestingPrerenderedPage = true; + // prerender if a crawler is detected foreach ($this->crawlerUserAgents as $crawlerUserAgent) { if (str_contains($userAgent, strtolower($crawlerUserAgent))) { $isRequestingPrerenderedPage = true; @@ -76,23 +133,33 @@ private function shouldShowPrerenderedPage(SymfonyRequest $request) if (!$isRequestingPrerenderedPage) return false; + // only check whitelist if it is not empty if ($this->whitelist) { if (!$this->isListed($requestUri, $this->whitelist)) { return false; } } + // only check blacklist if it is not empty if ($this->blacklist) { $uris[] = $requestUri; + // we also check for a blacklisted referer if ($referer) $uris[] = $referer; if ($this->isListed($uris, $this->blacklist)) { return false; } } + // Okay! Prerender please. return true; } + /** + * Prerender the page and return the Guzzle Response + * + * @param SymfonyRequest $request + * @return null|void + */ private function getPrerenderedPageResponse(SymfonyRequest $request) { $headers = [ @@ -103,8 +170,12 @@ private function getPrerenderedPageResponse(SymfonyRequest $request) } try { + // Return the Guzzle Response return $this->client->get('/' . urlencode($request->getUri()), compact('headers')); } catch (RequestException $exception) { + // In case of an exception, we only throw the exception if we are in debug mode. Otherwise, + // we return null and the handle() method will just pass the request to the next middleware + // and we do not show a prerendered page. if ($this->app['config']->get('app.debug')) { throw $exception; } @@ -112,6 +183,12 @@ private function getPrerenderedPageResponse(SymfonyRequest $request) } } + /** + * Convert a Guzzle Response to a Symfony Response + * + * @param GuzzleResponse $prerenderedResponse + * @return SymfonyResponse + */ private function buildSymfonyResponseFromGuzzleResponse(GuzzleResponse $prerenderedResponse) { $body = $prerenderedResponse->getBody(); @@ -120,6 +197,13 @@ private function buildSymfonyResponseFromGuzzleResponse(GuzzleResponse $prerende return new SymfonyResponse($body, $statusCode, $headers); } + /** + * Check whether one or more needles are in the given list + * + * @param $needles + * @param $list + * @return bool + */ private function isListed($needles, $list) { $needles = is_array($needles) ? $needles : [$needles];