diff --git a/core/lib/Drupal/Core/Routing/AcceptHeaderMatcher.php b/core/lib/Drupal/Core/Routing/AcceptHeaderMatcher.php index eee3056..34f0ae5 100644 --- a/core/lib/Drupal/Core/Routing/AcceptHeaderMatcher.php +++ b/core/lib/Drupal/Core/Routing/AcceptHeaderMatcher.php @@ -46,37 +46,34 @@ public function filter(RouteCollection $collection, Request $request) { $acceptable_formats = array_filter(array_map(array($request, 'getFormat'), $acceptable_mime_types)); $primary_format = $this->contentNegotiation->getContentType($request); - // Collect a list of routes that match the primary request content type. - $primary_matches = new RouteCollection(); - // List of routes that match any of multiple specified content types in the - // request, which should get a lower priority. - $somehow_matches = new RouteCollection(); - foreach ($collection as $name => $route) { // _format could be a |-delimited list of supported formats. $supported_formats = array_filter(explode('|', $route->getRequirement('_format'))); if (empty($supported_formats)) { - // No format restriction on the route, so it always matches. - $somehow_matches->add($name, $route); + // No format restriction on the route, so it always matches. Move it to + // the end of the collection by re-adding it. + $collection->add($name, $route); } elseif (in_array($primary_format, $supported_formats)) { - // Perfect match, which will get a higher priority. - $primary_matches->add($name, $route); + // Perfect match, which will get a higher priority by leaving the route + // on top of the list. } // The route partially matches if it doesn't care about format, if it // explicitly allows any format, or if one of its allowed formats is // in the request's list of acceptable formats. elseif (in_array('*/*', $acceptable_mime_types) || array_intersect($acceptable_formats, $supported_formats)) { - $somehow_matches->add($name, $route); + // Move it to the end of the list. + $collection->add($name, $route); + } + else { + // Remove the route if it does not match at all. + $collection->remove($name); } } - // Append the generic routes to the end, which will give them a lower - // priority. - $primary_matches->addCollection($somehow_matches); - if (count($primary_matches)) { - return $primary_matches; + if (count($collection)) { + return $collection; } // We do not throw a diff --git a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php index 1f59256..48b41db 100644 --- a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php +++ b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php @@ -173,6 +173,9 @@ protected function getRequestForPath($path, array $exclude) { // @todo Use the RequestHelper once https://drupal.org/node/2090293 is // fixed. $request = Request::create($this->request->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])) { diff --git a/core/tests/Drupal/Tests/Core/Routing/AcceptHeaderMatcherTest.php b/core/tests/Drupal/Tests/Core/Routing/AcceptHeaderMatcherTest.php index 2fb63cb..6080ed6 100644 --- a/core/tests/Drupal/Tests/Core/Routing/AcceptHeaderMatcherTest.php +++ b/core/tests/Drupal/Tests/Core/Routing/AcceptHeaderMatcherTest.php @@ -9,7 +9,7 @@ use Drupal\Core\ContentNegotiation; use Drupal\Core\Routing\AcceptHeaderMatcher; -use Drupal\system\Tests\Routing\RoutingFixtures; +use Drupal\Tests\Core\Routing\RoutingFixtures; use Drupal\Tests\UnitTestCase; use Symfony\Component\HttpFoundation\Request; diff --git a/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php b/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php index 3804462..9e8c8f5 100644 --- a/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php +++ b/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php @@ -8,7 +8,7 @@ namespace Drupal\Tests\Core\Routing; use Drupal\Core\Routing\ContentTypeHeaderMatcher; -use Drupal\system\Tests\Routing\RoutingFixtures; +use Drupal\Tests\Core\Routing\RoutingFixtures; use Drupal\Tests\UnitTestCase; use Symfony\Component\HttpFoundation\Request; diff --git a/core/tests/Drupal/Tests/Core/Routing/MimeTypeMatcherTest.php b/core/tests/Drupal/Tests/Core/Routing/MimeTypeMatcherTest.php deleted file mode 100644 index b407fe8..0000000 --- a/core/tests/Drupal/Tests/Core/Routing/MimeTypeMatcherTest.php +++ /dev/null @@ -1,112 +0,0 @@ - 'Partial matcher MIME types tests', - 'description' => 'Confirm that the mime types partial matcher is functioning properly.', - 'group' => 'Routing', - ); - } - - public function setUp() { - $this->fixtures = new RoutingFixtures(); - } - - /** - * Confirms that the MimeType matcher matches properly. - * - * @param string $accept_header - * The 'Accept` header to test. - * @param integer $routes_count - * The number of expected routes. - * @param string $null_route - * The route that is expected to be null. - * @param string $not_null_route - * The route that is expected to not be null. - * - * @dataProvider providerTestFilterRoutes - */ - public function testFilterRoutes($accept_header, $routes_count, $null_route, $not_null_route) { - - $matcher = new MimeTypeMatcher(); - $collection = $this->fixtures->sampleRouteCollection(); - - // Tests basic JSON request. - $request = Request::create('path/two', 'GET'); - $request->headers->set('Accept', $accept_header); - $routes = $matcher->filter($collection, $request); - $this->assertEquals($routes_count, count($routes), 'An incorrect number of routes was found.'); - $this->assertNull($routes->get($null_route), 'A route was found where it should be null.'); - $this->assertNotNull($routes->get($not_null_route), 'The expected route was not found.'); - } - - /** - * Provides test routes for testFilterRoutes. - * - * @return array - * An array of arrays, each containing the parameters necessary for the - * testFilterRoutes method. - */ - public function providerTestFilterRoutes() { - return array( - // Tests basic JSON request. - array('application/json, text/xml;q=0.9', 4, 'route_e', 'route_c'), - - // Tests JSON request with alternative JSON MIME type Accept header. - array('application/x-json, text/xml;q=0.9', 4, 'route_e', 'route_c'), - - // Tests basic HTML request. - array('text/html, text/xml;q=0.9', 4, 'route_c', 'route_e'), - ); - } - - /** - * Confirms that the MimeTypeMatcher matcher throws an exception for no-route. - * - * @expectedException Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException - */ - public function testNoRouteFound() { - $matcher = new MimeTypeMatcher(); - - // Remove the sample routes that would match any method. - $routes = $this->fixtures->sampleRouteCollection(); - $routes->remove('route_a'); - $routes->remove('route_b'); - $routes->remove('route_c'); - $routes->remove('route_d'); - - // This should throw NotAcceptableHttpException. - $request = Request::create('path/two', 'GET'); - $request->headers->set('Accept', 'application/json, text/xml;q=0.9'); - $routes = $matcher->filter($routes, $request); - } - -}