Skip to content

[Routing] refactored to support 405 Method Not Allowed responses #128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 22, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ protected function configure()
{
$this
->setDefinition(array(
new InputArgument('script_name', InputArgument::OPTIONAL, 'The script name of the application\'s front controller.')
new InputArgument('script_name', InputArgument::OPTIONAL, 'The script name of the application\'s front controller.'),
new InputOption('base-uri', null, InputOption::VALUE_REQUIRED, 'The base URI'),
))
->setName('router:dump-apache')
->setDescription('Dumps all routes as Apache rewrite rules')
Expand All @@ -58,6 +59,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
if ($input->getArgument('script_name')) {
$dumpOptions['script_name'] = $input->getArgument('script_name');
}
if ($input->getOption('base-uri')) {
$dumpOptions['base_uri'] = $input->getOption('base-uri');
}

$dumper = new ApacheMatcherDumper($router->getRouteCollection());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ class ExceptionController extends ContainerAware
* @param FlattenException $exception A FlattenException instance
* @param DebugLoggerInterface $logger A DebugLoggerInterface instance
* @param string $format The format to use for rendering (html, xml, ...)
* @param integer $code An HTTP response code
* @param string $message An HTTP response status message
* @param array $headers HTTP response headers
*
* @throws \InvalidArgumentException When the exception template does not exist
*/
public function showAction(FlattenException $exception, DebugLoggerInterface $logger = null, $format = 'html')
public function showAction(FlattenException $exception, DebugLoggerInterface $logger = null, $format = 'html', $code = 500, $message = null, array $headers = array())
{
$this->container->get('request')->setRequestFormat($format);

Expand All @@ -45,8 +48,6 @@ public function showAction(FlattenException $exception, DebugLoggerInterface $lo
$currentContent .= ob_get_clean();
}

$code = $this->getStatusCode($exception);

$name = $this->container->get('kernel')->isDebug() ? 'exception' : 'error';
if ($this->container->get('kernel')->isDebug() && 'html' == $format) {
$name = 'exception_full';
Expand All @@ -63,27 +64,16 @@ public function showAction(FlattenException $exception, DebugLoggerInterface $lo
$template,
array(
'status_code' => $code,
'status_text' => Response::$statusTexts[$code],
'status_text' => $message ?: Response::$statusTexts[$code],
'exception' => $exception,
'logger' => $logger,
'currentContent' => $currentContent,
)
);

$response->setStatusCode($code);
$response->setStatusCode($code, $message);
$response->headers->replace($headers);

return $response;
}

protected function getStatusCode(FlattenException $exception)
{
switch ($exception->getClass()) {
case 'Symfony\Component\Security\Core\Exception\AccessDeniedException':
return 403;
case 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException':
return 404;
default:
return 500;
}
}
}
24 changes: 20 additions & 4 deletions src/Symfony/Bundle/FrameworkBundle/RequestListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Matcher\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Matcher\Exception\NotFoundException;
use Symfony\Component\Routing\RouterInterface;

/**
* RequestListener.
Expand Down Expand Up @@ -83,7 +87,9 @@ protected function initializeRequestAttributes(Request $request, $master)
}

// add attributes based on the path info (routing)
if (false !== $parameters = $this->router->match($request->getPathInfo())) {
try {
$parameters = $this->router->match($request->getPathInfo());

if (null !== $this->logger) {
$this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], json_encode($parameters)));
}
Expand All @@ -93,8 +99,18 @@ protected function initializeRequestAttributes(Request $request, $master)
if ($locale = $request->attributes->get('_locale')) {
$request->getSession()->setLocale($locale);
}
} elseif (null !== $this->logger) {
$this->logger->err(sprintf('No route found for %s', $request->getPathInfo()));
} catch (NotFoundException $e) {
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
if (null !== $this->logger) {
$this->logger->err($message);
}
throw new NotFoundHttpException('Not Found', $message, 0, $e);
} catch (MethodNotAllowedException $e) {
$message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods())));
if (null !== $this->logger) {
$this->logger->err($message);
}
throw new MethodNotAllowedHttpException($e->getAllowedMethods(), 'Method Not Allowed', $message, 0, $e);
}
}
}
11 changes: 11 additions & 0 deletions src/Symfony/Component/HttpKernel/Debug/ExceptionListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Exception\FlattenException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpFoundation\Request;

/**
Expand Down Expand Up @@ -63,6 +64,16 @@ public function onCoreException(GetResponseForExceptionEvent $event)
'format' => 0 === strncasecmp(PHP_SAPI, 'cli', 3) ? 'txt' : $request->getRequestFormat(),
);

$attributes += $exception instanceof HttpExceptionInterface ? array(
'code' => $exception->getStatusCode(),
'message' => $exception->getStatusMessage(),
'headers' => $exception->getHeaders(),
) : array(
'code' => 500,
'message' => 'Internal Server Error',
'headers' => array(),
);

$request = $request->duplicate(null, null, $attributes);

try {
Expand Down
48 changes: 48 additions & 0 deletions src/Symfony/Component/HttpKernel/Exception/BaseHttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\HttpKernel\Exception;

/**
* BaseHttpException.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
abstract class BaseHttpException extends \RuntimeException implements HttpExceptionInterface
{
protected $statusCode;
protected $statusMessage;
protected $headers;

public function __construct($statusCode, $statusMessage, array $headers = array(), $message = null, $code = 0, \Exception $previous = null)
{
$this->statusCode = $statusCode;
$this->statusMessage = $statusMessage;
$this->headers = $headers;

parent::__construct($message, 0, $previous);
}

public function getStatusCode()
{
return $this->statusCode;
}

public function getStatusMessage()
{
return $this->statusMessage;
}

public function getHeaders()
{
return $this->headers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\HttpKernel\Exception;

/**
* Interface for HTTP error exceptions.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
interface HttpExceptionInterface
{
/**
* Returns the status code.
*
* @return integer An HTTP response status code
*/
function getStatusCode();

/**
* Return the status message.
*
* @return string An HTTP response status message
*/
function getStatusMessage();

/**
* Returns response headers.
*
* @return array Response headers
*/
function getHeaders();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\HttpKernel\Exception;

/**
* MethodNotAllowedHttpException.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class MethodNotAllowedHttpException extends BaseHttpException
{
/**
* Constructor.
*
* WARNING: The status message will be sent as a response header
* regardless of debug mode.
*
* @param array $allow An array of allowed methods
* @param string $statusMessage The HTTP response status message
* @param string $message The internal exception message
* @param integer $code The internal exception code
* @param Exception $previous The previous exception
*/
public function __construct(array $allow, $statusMessage = 'Method Not Allowed', $message = null, $code = 0, \Exception $previous = null)
{
$headers = array('Allow' => strtoupper(implode(', ', $allow)));

parent::__construct(405, $statusMessage, $headers, $message ?: $statusMessage, $code, $previous);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class NotFoundHttpException extends \RuntimeException
class NotFoundHttpException extends BaseHttpException
{
public function __construct($message = 'Not Found', \Exception $previous = null)
/**
* Constructor.
*
* WARNING: The status message will be sent as a response header
* regardless of debug mode.
*
* @param string $statusMessage The HTTP response status message
* @param string $message The internal exception message
* @param integer $code The internal exception code
* @param Exception $previous The previous exception
*/
public function __construct($statusMessage = 'Not Found', $message = null, $code = 0, \Exception $previous = null)
{
parent::__construct($message, 404, $previous);
parent::__construct(404, $statusMessage, array(), $message ?: $statusMessage, $code, $previous);
}
}
Loading