/** * Converts the request path to a system path. * * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event * The Event to process. */ public function onKernelRequestConvertPath(GetResponseEvent $event) { $request = $event->getRequest(); $path = trim($request->getPathInfo(), '/'); $path = $this->pathProcessor->processInbound($path, $request); $request->attributes->set('_system_path', $path); // Set the cache key on the alias manager cache decorator. if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { $this->aliasManager->setCacheKey($path); } }
/** * Handles the redirect if any found. * * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event * The event to process. */ public function onKernelRequestCheckRedirect(GetResponseEvent $event) { $request = $event->getRequest(); if (!$this->checker->canRedirect($request)) { return; } // Get URL info and process it to be used for hash generation. parse_str($request->getQueryString(), $request_query); // Do the inbound processing so that for example language prefixes are // removed. $path = $this->pathProcessor->processInbound($request->getPathInfo(), $request); $path = ltrim($path, '/'); $this->context->fromRequest($request); try { $redirect = $this->redirectRepository->findMatchingRedirect($path, $request_query, $this->languageManager->getCurrentLanguage()->getId()); } catch (RedirectLoopException $e) { \Drupal::logger('redirect')->warning($e->getMessage()); $response = new Response(); $response->setStatusCode(503); $response->setContent('Service unavailable'); $event->setResponse($response); return; } if (!empty($redirect)) { // Handle internal path. $url = $redirect->getRedirectUrl(); if ($this->config->get('passthrough_querystring')) { $url->setOption('query', (array) $url->getOption('query') + $request_query); } $headers = ['X-Redirect-ID' => $redirect->id()]; $response = new TrustedRedirectResponse($url->setAbsolute()->toString(), $redirect->getStatusCode(), $headers); $response->addCacheableDependency($redirect); $event->setResponse($response); } }
/** * Matches a path in the router. * * @param string $path * The request path. * @param array $exclude * An array of paths or system paths to skip. * * @return \Symfony\Component\HttpFoundation\Request * A populated request object or NULL if the path couldn't be matched. */ protected function getRequestForPath($path, array $exclude) { if (!empty($exclude[$path])) { return NULL; } // @todo Use the RequestHelper once https://drupal.org/node/2090293 is // fixed. $request = Request::create($this->context->getBaseUrl() . '/' . $path); // Performance optimization: set a short accept header to reduce overhead in // AcceptHeaderMatcher when matching the request. $request->headers->set('Accept', 'text/html'); // Find the system path by resolving aliases, language prefix, etc. $processed = $this->pathProcessor->processInbound($path, $request); if (empty($processed) || !empty($exclude[$processed])) { // This resolves to the front page, which we already add. return NULL; } $request->attributes->set('_system_path', $processed); // Attempt to match this path to provide a fully built request. try { $request->attributes->add($this->router->matchRequest($request)); return $request; } catch (ParamNotConvertedException $e) { return NULL; } catch (ResourceNotFoundException $e) { return NULL; } catch (MethodNotAllowedException $e) { return NULL; } catch (AccessDeniedHttpException $e) { return NULL; } }
/** * Tests the getUrlIfValid() method where there is no access. */ public function testGetUrlIfValidWithoutAccess() { $this->account->expects($this->once())->method('hasPermission')->with('link to any page')->willReturn(FALSE); $this->accessAwareRouter->expects($this->once())->method('match')->with('/test-path')->willThrowException(new AccessDeniedHttpException()); $this->pathProcessor->expects($this->once())->method('processInbound')->willReturnArgument(0); $url = $this->pathValidator->getUrlIfValid('test-path'); $this->assertFalse($url); }
/** * Tests the getUrlIfValidWithoutAccessCheck() method. * * @covers ::getUrlIfValidWithoutAccessCheck */ public function testGetUrlIfValidWithoutAccessCheck() { $this->account->expects($this->never())->method('hasPermission')->with('link to any page'); $this->accessAwareRouter->expects($this->never())->method('match'); $this->accessUnawareRouter->expects($this->once())->method('match')->with('/test-path')->willReturn([RouteObjectInterface::ROUTE_NAME => 'test_route', '_raw_variables' => new ParameterBag(['key' => 'value'])]); $this->pathProcessor->expects($this->once())->method('processInbound')->willReturnArgument(0); $url = $this->pathValidator->getUrlIfValidWithoutAccessCheck('test-path'); $this->assertInstanceOf('Drupal\\Core\\Url', $url); $this->assertEquals('test_route', $url->getRouteName()); $this->assertEquals(['key' => 'value'], $url->getRouteParameters()); }
/** * Gets the matched attributes for a given path. * * @param string $path * The path to check. * @param \Symfony\Component\HttpFoundation\Request $request * A request object with the given path. * * @return array|bool * An array of request attributes of FALSE if an exception was thrown. */ protected function getPathAttributes($path, Request $request) { if ($this->account->hasPermission('link to any page')) { $router = $this->accessUnawareRouter; } else { $router = $this->accessAwareRouter; } $path = $this->pathProcessor->processInbound($path, $request); try { return $router->match('/' . $path); } catch (ResourceNotFoundException $e) { return FALSE; } catch (ParamNotConvertedException $e) { return FALSE; } catch (AccessDeniedHttpException $e) { return FALSE; } }
/** * Matches a path in the router. * * @param \Symfony\Component\HttpFoundation\Request $request * Page request object. * @param string $path * Path to look up. * * @return \Symfony\Component\HttpFoundation\Request|null * A populated request object or NULL if the patch could not be matched. */ protected function getRequestForPath(Request $request, $path) { // @todo Use RequestHelper::duplicate once https://drupal.org/node/2090293 // is fixed. $route_request = Request::create($request->getBaseUrl() . '/' . $path); // Find the system path by resolving aliases, language prefix, etc. $processed = $this->pathProcessor->processInbound($path, $route_request); $route_request->attributes->set('_system_path', $processed); // Attempt to match this path to provide a fully built request. try { $route_request->attributes->add($this->router->matchRequest($route_request)); return $route_request; } catch (ParamNotConvertedException $e) { return NULL; } catch (ResourceNotFoundException $e) { return NULL; } }
/** * Finds routes that may potentially match the request. * * This may return a mixed list of class instances, but all routes returned * must extend the core symfony route. The classes may also implement * RouteObjectInterface to link to a content document. * * This method may not throw an exception based on implementation specific * restrictions on the url. That case is considered a not found - returning * an empty array. Exceptions are only used to abort the whole request in * case something is seriously broken, like the storage backend being down. * * Note that implementations may not implement an optimal matching * algorithm, simply a reasonable first pass. That allows for potentially * very large route sets to be filtered down to likely candidates, which * may then be filtered in memory more completely. * * @param Request $request A request against which to match. * * @return \Symfony\Component\Routing\RouteCollection with all urls that * could potentially match $request. Empty collection if nothing can * match. */ public function getRouteCollectionForRequest(Request $request) { // Cache both the system path as well as route parameters and matching // routes. $cid = 'route:' . $request->getPathInfo() . ':' . $request->getQueryString(); if ($cached = $this->cache->get($cid)) { $this->currentPath->setPath($cached->data['path'], $request); $request->query->replace($cached->data['query']); return $cached->data['routes']; } else { // Just trim on the right side. $path = $request->getPathInfo(); $path = $path === '/' ? $path : rtrim($request->getPathInfo(), '/'); $path = $this->pathProcessor->processInbound($path, $request); $this->currentPath->setPath($path, $request); // Incoming path processors may also set query parameters. $query_parameters = $request->query->all(); $routes = $this->getRoutesByPath(rtrim($path, '/')); $cache_value = ['path' => $path, 'query' => $query_parameters, 'routes' => $routes]; $this->cache->set($cid, $cache_value, CacheBackendInterface::CACHE_PERMANENT, ['route_match']); return $routes; } }
/** * {@inheritdoc} */ public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleableMetadata = NULL) { if (isset($options['absolute']) && $options['absolute']) { return $path; } $original_path = $path; $subpath = []; $max_depth = $this->getMaxDepth(); $i = 0; while (($path_array = explode('/', ltrim($path, '/'))) && ($max_depth === 0 || $i < $max_depth)) { $i++; $subpath[] = array_pop($path_array); if (empty($path_array)) { break; } $path = '/' . implode('/', $path_array); $processed_path = $this->pathProcessor->processOutbound($path, $options, $request); if ($processed_path !== $path) { $path = $processed_path . '/' . implode('/', array_reverse($subpath)); return $path; } } return $original_path; }
protected function setupStubPathProcessor() { $this->pathProcessor->expects($this->any())->method('processInbound')->will($this->returnArgument(0)); }