8000 Show full URI when route not found · symfony/symfony@09d6f6b · GitHub
[go: up one dir, main page]

Skip to content

Commit 09d6f6b

Browse files
committed
Show full URI when route not found
When accessing a route that does not exist, Symfony throws a `NotFoundHttpException` that says `No route found for "POST /path"`. On some projects this might be good enough to find the root cause, but on projects that have lots of routes on different hosts, it becomes hard to understand how the request was initiated. Was it done over HTTP or HTTPS? What was the hostname? Did the user specify a port? To make this easier, we now show the full URI of the path, like this: `No route found for "POST https://www.symfony.com/path"`.
1 parent b8e76de commit 09d6f6b

File tree

2 files changed

+76
-11
lines changed

2 files changed

+76
-11
lines changed

src/Symfony/Component/HttpKernel/EventListener/RouterListener.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ public function onKernelRequest(RequestEvent $event)
127127
unset($parameters['_route'], $parameters['_controller']);
128128
$request->attributes->set('_route_params', $parameters);
129129
} catch (ResourceNotFoundException $e) {
130-
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
130+
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getUriForPath($request->getPathInfo()));
131131

132132
if ($referer = $request->headers->get('referer')) {
133133
$message .= sprintf(' (from "%s")', $referer);
134134
}
135135

136136
throw new NotFoundHttpException($message, $e);
137137
} catch (MethodNotAllowedException $e) {
138-
$message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), implode(', ', $e->getAllowedMethods()));
138+
$message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getUriForPath($request->getPathInfo()), implode(', ', $e->getAllowedMethods()));
139139

140140
throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e);
141141
}

src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\HttpKernel\Tests\EventListener;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Psr\Log\LoggerInterface;
1516
use Symfony\Component\EventDispatcher\EventDispatcher;
1617
use Symfony\Component\HttpFoundation\Request;
1718
use Symfony\Component\HttpFoundation\RequestStack;
@@ -22,9 +23,16 @@
2223
use Symfony\Component\HttpKernel\EventListener\ErrorListener;
2324
use Symfony\Component\HttpKernel\EventListener\RouterListener;
2425
use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener;
26+
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
27+
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
28+
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2529
use Symfony\Component\HttpKernel\HttpKernel;
2630
use Symfony\Component\HttpKernel\HttpKernelInterface;
31+
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
2732
use Symfony\Component\Routing\Exception\NoConfigurationException;
33+
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
34+
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
35+
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
2836
use Symfony\Component\Routing\RequestContext;
2937

3038
class RouterListenerTest extends TestCase
@@ -41,7 +49,7 @@ protected function setUp(): void
4149
*/
4250
public function testPort($defaultHttpPort, $defaultHttpsPort, $uri, $expectedHttpPort, $expectedHttpsPort)
4351
{
44-
$urlMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\UrlMatcherInterface::class)
52+
$urlMatcher = $this->getMockBuilder(UrlMatcherInterface::class)
4553
->disableOriginalConstructor()
4654
->getMock();
4755
$context = new RequestContext();
@@ -91,7 +99,7 @@ public function testRequestMatcher()
9199
$request = Request::create('http://localhost/');
92100
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
93101

94-
$requestMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\RequestMatcherInterface::class)->getMock();
102+
$requestMatcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
95103
$requestMatcher->expects($this->once())
96104
->method('matchRequest')
97105
->with($this->isInstanceOf(Request::class))
@@ -107,7 +115,7 @@ public function testSubRequestWithDifferentMethod()
107115
$request = Request::create('http://localhost/', 'post');
108116
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
109117

110-
$requestMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\RequestMatcherInterface::class)->getMock();
118+
$requestMatcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
111119
$requestMatcher->expects($this->any())
112120
->method('matchRequest')
113121
->with($this->isInstanceOf(Request::class))
@@ -133,12 +141,12 @@ public function testSubRequestWithDifferentMethod()
133141
*/
134142
public function testLoggingParameter($parameter, $log, $parameters)
135143
{
136-
$requestMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\RequestMatcherInterface::class)->getMock();
144+
$requestMatcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
137145
$requestMatcher->expects($this->once())
138146
->method('matchRequest')
139147
->willReturn($parameter);
140148

141-
$logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)->getMock();
149+
$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
142150
$logger->expects($this->once())
143151
->method('info')
144152
->with($this->equalTo($log), $this->equalTo($parameters));
@@ -162,7 +170,7 @@ public function testWithBadRequest()
162170
{
163171
$requestStack = new RequestStack();
164172

165-
$requestMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\RequestMatcherInterface::class)->getMock();
173+
$requestMatcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
166174
$requestMatcher->expects($this->never())->method('matchRequest');
167175

168176
$dispatcher = new EventDispatcher();
@@ -184,7 +192,7 @@ public function testNoRoutingConfigurationResponse()
184192
{
185193
$requestStack = new RequestStack();
186194

187-
$requestMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\RequestMatcherInterface::class)->getMock();
195+
$requestMatcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
188196
$requestMatcher
189197
->expects($this->once())
190198
->method('matchRequest')
@@ -204,14 +212,71 @@ public function testNoRoutingConfigurationResponse()
204212

205213
public function testRequestWithBadHost()
206214
{
207-
$this->expectException(\Symfony\Component\HttpKernel\Exception\BadRequestHttpException::class);
215+
$this->expectException(BadRequestHttpException::class);
208216
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
209217
$request = Request::create('http://bad host %22/');
210218
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
211219

212-
$requestMatcher = $this->getMockBuilder(\Symfony\Component\Routing\Matcher\RequestMatcherInterface::class)->getMock();
220+
$requestMatcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
213221

214222
$listener = new RouterListener($requestMatcher, $this->requestStack, new RequestContext());
215223
$listener->onKernelRequest($event);
216224
}
225+
226+
public function testResourceNotFoundException()
227+
{
228+
$this->expectException(NotFoundHttpException::class);
229+
$this->expectExceptionMessage('No route found for "GET https://www.symfony.com/path" (from "https://www.google.com")');
230+
231+
$context = new RequestContext();
232+
233+
$urlMatcher = $this->getMockBuilder(UrlMatcherInterface::class)
234+
->disableOriginalConstructor()
235+
->getMock();
236+
237+
$urlMatcher->expects($this->any())
238+
->method('getContext')
239+
->willReturn($context);
240+
241+
$urlMatcher->expects($this->any())
242+
->method('match')
243+
->willThrowException(new ResourceNotFoundException());
244+
245+
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
246+
$request = Request::create('https://www.symfony.com/path');
247+
$request->headers->set('referer', 'https://www.google.com');
248+
249+
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
250+
251+
$listener = new RouterListener($urlMatcher, $this->requestStack);
252+
$listener->onKernelRequest($event);
253+
}
254+
255+
public function testMethodNotAllowedException()
256+
{
257+
$this->expectException(MethodNotAllowedHttpException::class);
258+
$this->expectExceptionMessage('No route found for "GET https://www.symfony.com/path": Method Not Allowed (Allow: POST)');
259+
260+
$context = new RequestContext();
261+
262+
$urlMatcher = $this->getMockBuilder(UrlMatcherInterface::class)
263+
->disableOriginalConstructor()
264+
->getMock();
265+
266+
$urlMatcher->expects($this->any())
267+
->method('getContext')
268+
->willReturn($context);
269+
270+
$urlMatcher->expects($this->any())
271+
->method('match')
272+
->willThrowException(new MethodNotAllowedException(['POST']));
273+
274+
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
275+
$request = Request::create('https://www.symfony.com/path');
276+
277+
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
278+
279+
$listener = new RouterListener($urlMatcher, $this->requestStack);
280+
$listener->onKernelRequest($event);
281+
}
217282
}

0 commit comments

Comments
 (0)
0