Merge branch '2.2' into 2.3

* 2.2:
  fixed Client when using the terminable event
  Fix problem with Windows file links (backslash in JavaScript string)
  [Security] fixed wrong phpdoc
  [Routing] removed extra argument
  [HttpFoundation] Header `HTTP_X_FORWARDED_PROTO` can contain various values Some proxies use `ssl` instead of `https`, as well as Lighttpd mod_proxy allows value chaining (`https, http`, where `https` is always first when request is encrypted).
  Added doc comments

Conflicts:
	src/Symfony/Component/HttpFoundation/Request.php
This commit is contained in:
Fabien Potencier 2013-09-29 21:41:41 +02:00
commit bc256f9da4
24 changed files with 117 additions and 20 deletions

View File

@ -160,7 +160,7 @@ class Client extends BaseClient
$profilerCode = '$kernel->getContainer()->get(\'profiler\')->enable();'; $profilerCode = '$kernel->getContainer()->get(\'profiler\')->enable();';
} }
return <<<EOF $code = <<<EOF
<?php <?php
if ('$autoloader') { if ('$autoloader') {
@ -171,7 +171,10 @@ require_once '$path';
\$kernel = unserialize('$kernel'); \$kernel = unserialize('$kernel');
\$kernel->boot(); \$kernel->boot();
$profilerCode $profilerCode
echo serialize(\$kernel->handle(unserialize('$request')));
\$request = unserialize('$request');
EOF; EOF;
return $code.$this->getHandleScript();
} }
} }

View File

@ -5,7 +5,7 @@
{% if collector.controller.class is defined %} {% if collector.controller.class is defined %}
{% set link = collector.controller.file|file_link(collector.controller.line) %} {% set link = collector.controller.file|file_link(collector.controller.line) %}
<span class="sf-toolbar-info-class sf-toolbar-info-with-next-pointer">{{ collector.controller.class|abbr_class }}</span> <span class="sf-toolbar-info-class sf-toolbar-info-with-next-pointer">{{ collector.controller.class|abbr_class }}</span>
<span class="sf-toolbar-info-method" onclick="{% if link %}window.location='{{link}}';window.event.stopPropagation();return false;{% endif %}"> <span class="sf-toolbar-info-method" onclick="{% if link %}window.location='{{link|e('js')}}';window.event.stopPropagation();return false;{% endif %}">
{{ collector.controller.method }} {{ collector.controller.method }}
</span> </span>
{% else %} {% else %}

View File

@ -1084,7 +1084,7 @@ class Request
public function isSecure() public function isSecure()
{ {
if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) { if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
return in_array(strtolower($proto), array('https', 'on', '1')); return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1'));
} }
return 'on' == strtolower($this->server->get('HTTPS')) || 1 == $this->server->get('HTTPS'); return 'on' == strtolower($this->server->get('HTTPS')) || 1 == $this->server->get('HTTPS');

View File

@ -1420,6 +1420,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(443, $request->getPort()); $this->assertEquals(443, $request->getPort());
$this->assertTrue($request->isSecure()); $this->assertTrue($request->isSecure());
// check various X_FORWARDED_PROTO header values
$request->headers->set('X_FORWARDED_PROTO', 'ssl');
$this->assertTrue($request->isSecure());
$request->headers->set('X_FORWARDED_PROTO', 'https, http');
$this->assertTrue($request->isSecure());
// custom header names // custom header names
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST');

View File

@ -104,7 +104,7 @@ class Client extends BaseClient
$requirePath = str_replace("'", "\\'", $r->getFileName()); $requirePath = str_replace("'", "\\'", $r->getFileName());
$symfonyPath = str_replace("'", "\\'", realpath(__DIR__.'/../../..')); $symfonyPath = str_replace("'", "\\'", realpath(__DIR__.'/../../..'));
return <<<EOF $code = <<<EOF
<?php <?php
require_once '$requirePath'; require_once '$requirePath';
@ -114,7 +114,22 @@ require_once '$requirePath';
\$loader->register(); \$loader->register();
\$kernel = unserialize('$kernel'); \$kernel = unserialize('$kernel');
echo serialize(\$kernel->handle(unserialize('$request'))); \$request = unserialize('$request');
EOF;
return $code.$this->getHandleScript();
}
protected function getHandleScript()
{
return <<<'EOF'
$response = $kernel->handle($request);
if ($kernel instanceof Symfony\Component\HttpKernel\TerminableInterface) {
$kernel->terminate($request, $response);
}
echo serialize($response);
EOF; EOF;
} }

View File

@ -232,7 +232,7 @@ class Router implements RouterInterface
$class = $this->options['matcher_cache_class']; $class = $this->options['matcher_cache_class'];
$cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
if (!$cache->isFresh($class)) { if (!$cache->isFresh()) {
$dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection()); $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
$options = array( $options = array(
@ -264,7 +264,7 @@ class Router implements RouterInterface
} else { } else {
$class = $this->options['generator_cache_class']; $class = $this->options['generator_cache_class'];
$cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
if (!$cache->isFresh($class)) { if (!$cache->isFresh()) {
$dumper = new $this->options['generator_dumper_class']($this->getRouteCollection()); $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
$options = array( $options = array(

View File

@ -36,6 +36,9 @@ class AccessMap implements AccessMapInterface
$this->map[] = array($requestMatcher, $roles, $channel); $this->map[] = array($requestMatcher, $roles, $channel);
} }
/**
* {@inheritDoc}
*/
public function getPatterns(Request $request) public function getPatterns(Request $request)
{ {
foreach ($this->map as $elements) { foreach ($this->map as $elements) {

View File

@ -64,7 +64,7 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle
{ {
if ($failureUrl = $request->get($this->options['failure_path_parameter'], null, true)) { if ($failureUrl = $request->get($this->options['failure_path_parameter'], null, true)) {
$this->options['failure_path'] = $failureUrl; $this->options['failure_path'] = $failureUrl;
} }
if (null === $this->options['failure_path']) { if (null === $this->options['failure_path']) {
$this->options['failure_path'] = $this->options['login_path']; $this->options['failure_path'] = $this->options['login_path'];

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Security\Http\Authorization; namespace Symfony\Component\Security\Http\Authorization;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;

View File

@ -30,6 +30,9 @@ class BasicAuthenticationEntryPoint implements AuthenticationEntryPointInterface
$this->realmName = $realmName; $this->realmName = $realmName;
} }
/**
* {@inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null) public function start(Request $request, AuthenticationException $authException = null)
{ {
$response = new Response(); $response = new Response();

View File

@ -38,6 +38,9 @@ class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterfac
$this->logger = $logger; $this->logger = $logger;
} }
/**
* {@inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null) public function start(Request $request, AuthenticationException $authException = null)
{ {
$expiryTime = microtime(true) + $this->nonceValiditySeconds * 1000; $expiryTime = microtime(true) + $this->nonceValiditySeconds * 1000;
@ -62,11 +65,17 @@ class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterfac
return $response; return $response;
} }
/**
* @return string
*/
public function getKey() public function getKey()
{ {
return $this->key; return $this->key;
} }
/**
* @return string
*/
public function getRealmName() public function getRealmName()
{ {
return $this->realmName; return $this->realmName;

View File

@ -30,7 +30,7 @@ class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface
private $httpUtils; private $httpUtils;
/** /**
* Constructor * Constructor.
* *
* @param HttpKernelInterface $kernel * @param HttpKernelInterface $kernel
* @param HttpUtils $httpUtils An HttpUtils instance * @param HttpUtils $httpUtils An HttpUtils instance

View File

@ -34,6 +34,9 @@ class RetryAuthenticationEntryPoint implements AuthenticationEntryPointInterface
$this->httpsPort = $httpsPort; $this->httpsPort = $httpsPort;
} }
/**
* {@inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null) public function start(Request $request, AuthenticationException $authException = null)
{ {
$scheme = $request->isSecure() ? 'http' : 'https'; $scheme = $request->isSecure() ? 'http' : 'https';

View File

@ -15,10 +15,14 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* InteractiveLoginEvent
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class InteractiveLoginEvent extends Event class InteractiveLoginEvent extends Event
{ {
private $request; private $request;
private $authenticationToken; private $authenticationToken;
/** /**

View File

@ -15,10 +15,14 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
/**
* SwitchUserEvent
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SwitchUserEvent extends Event class SwitchUserEvent extends Event
{ {
private $request; private $request;
private $targetUser; private $targetUser;
public function __construct(Request $request, UserInterface $targetUser) public function __construct(Request $request, UserInterface $targetUser)
@ -27,11 +31,17 @@ class SwitchUserEvent extends Event
$this->targetUser = $targetUser; $this->targetUser = $targetUser;
} }
/**
* @return Request
*/
public function getRequest() public function getRequest()
{ {
return $this->request; return $this->request;
} }
/**
* @return UserInterface
*/
public function getTargetUser() public function getTargetUser()
{ {
return $this->targetUser; return $this->targetUser;

View File

@ -71,6 +71,9 @@ class Firewall implements EventSubscriberInterface
} }
} }
/**
* {@inheritDoc}
*/
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return array(KernelEvents::REQUEST => array('onKernelRequest', 8)); return array(KernelEvents::REQUEST => array('onKernelRequest', 8));

View File

@ -161,6 +161,13 @@ class ExceptionListener
$event->setResponse($response); $event->setResponse($response);
} }
/**
* @param Request $request
* @param AuthenticationException $authException
*
* @return Response
* @throws AuthenticationException
*/
private function startAuthentication(Request $request, AuthenticationException $authException) private function startAuthentication(Request $request, AuthenticationException $authException)
{ {
if (null === $this->authenticationEntryPoint) { if (null === $this->authenticationEntryPoint) {
@ -181,6 +188,9 @@ class ExceptionListener
return $this->authenticationEntryPoint->start($request, $authException); return $this->authenticationEntryPoint->start($request, $authException);
} }
/**
* @param Request $request
*/
protected function setTargetPath(Request $request) protected function setTargetPath(Request $request)
{ {
// session isn't required when using http basic authentication mechanism for example // session isn't required when using http basic authentication mechanism for example

View File

@ -37,7 +37,7 @@ class LogoutListener implements ListenerInterface
private $csrfProvider; private $csrfProvider;
/** /**
* Constructor * Constructor.
* *
* @param SecurityContextInterface $securityContext * @param SecurityContextInterface $securityContext
* @param HttpUtils $httpUtils An HttpUtilsInterface instance * @param HttpUtils $httpUtils An HttpUtilsInterface instance
@ -77,9 +77,8 @@ class LogoutListener implements ListenerInterface
* *
* @param GetResponseEvent $event A GetResponseEvent instance * @param GetResponseEvent $event A GetResponseEvent instance
* *
* @throws InvalidCsrfTokenException if the CSRF token is invalid * @throws LogoutException if the CSRF token is invalid
* @throws \RuntimeException if the LogoutSuccessHandlerInterface instance does not return a response * @throws \RuntimeException if the LogoutSuccessHandlerInterface instance does not return a response
* @throws LogoutException
*/ */
public function handle(GetResponseEvent $event) public function handle(GetResponseEvent $event)
{ {

View File

@ -35,7 +35,7 @@ class RememberMeListener implements ListenerInterface
private $dispatcher; private $dispatcher;
/** /**
* Constructor * Constructor.
* *
* @param SecurityContextInterface $securityContext * @param SecurityContextInterface $securityContext
* @param RememberMeServicesInterface $rememberMeServices * @param RememberMeServicesInterface $rememberMeServices

View File

@ -36,6 +36,9 @@ class X509AuthenticationListener extends AbstractPreAuthenticatedListener
$this->credentialKey = $credentialKey; $this->credentialKey = $credentialKey;
} }
/**
* {@inheritdoc}
*/
protected function getPreAuthenticatedData(Request $request) protected function getPreAuthenticatedData(Request $request)
{ {
if (!$request->server->has($this->userKey)) { if (!$request->server->has($this->userKey)) {

View File

@ -25,11 +25,19 @@ class FirewallMap implements FirewallMapInterface
{ {
private $map = array(); private $map = array();
/**
* @param RequestMatcherInterface $requestMatcher
* @param array $listeners
* @param ExceptionListener $exceptionListener
*/
public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null) public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null)
{ {
$this->map[] = array($requestMatcher, $listeners, $exceptionListener); $this->map[] = array($requestMatcher, $listeners, $exceptionListener);
} }
/**
* {@inheritDoc}
*/
public function getListeners(Request $request) public function getListeners(Request $request)
{ {
foreach ($this->map as $elements) { foreach ($this->map as $elements) {

View File

@ -20,7 +20,6 @@ use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\HttpFoundation\Response;
/** /**
* Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs. * Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs.
@ -37,6 +36,8 @@ class HttpUtils
* *
* @param UrlGeneratorInterface $urlGenerator A UrlGeneratorInterface instance * @param UrlGeneratorInterface $urlGenerator A UrlGeneratorInterface instance
* @param UrlMatcherInterface|RequestMatcherInterface $urlMatcher The Url or Request matcher * @param UrlMatcherInterface|RequestMatcherInterface $urlMatcher The Url or Request matcher
*
* @throws \InvalidArgumentException
*/ */
public function __construct(UrlGeneratorInterface $urlGenerator = null, $urlMatcher = null) public function __construct(UrlGeneratorInterface $urlGenerator = null, $urlMatcher = null)
{ {
@ -54,7 +55,7 @@ class HttpUtils
* @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
* @param integer $status The status code * @param integer $status The status code
* *
* @return Response A RedirectResponse instance * @return RedirectResponse A RedirectResponse instance
*/ */
public function createRedirectResponse(Request $request, $path, $status = 302) public function createRedirectResponse(Request $request, $path, $status = 302)
{ {
@ -123,9 +124,11 @@ class HttpUtils
* Generates a URI, based on the given path or absolute URL. * Generates a URI, based on the given path or absolute URL.
* *
* @param Request $request A Request instance * @param Request $request A Request instance
* @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
* *
* @return string An absolute URL * @return string An absolute URL
*
* @throws \LogicException
*/ */
public function generateUri($request, $path) public function generateUri($request, $path)
{ {

View File

@ -40,7 +40,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
private $userProviders; private $userProviders;
/** /**
* Constructor * Constructor.
* *
* @param array $userProviders * @param array $userProviders
* @param string $key * @param string $key
@ -80,6 +80,9 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
return $this->options['remember_me_parameter']; return $this->options['remember_me_parameter'];
} }
/**
* @return string
*/
public function getKey() public function getKey()
{ {
return $this->key; return $this->key;
@ -94,6 +97,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
* @return TokenInterface|null * @return TokenInterface|null
* *
* @throws CookieTheftException * @throws CookieTheftException
* @throws \RuntimeException
*/ */
final public function autoLogin(Request $request) final public function autoLogin(Request $request)
{ {
@ -219,6 +223,9 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
*/ */
abstract protected function processAutoLoginCookie(array $cookieParts, Request $request); abstract protected function processAutoLoginCookie(array $cookieParts, Request $request);
/**
* @param Request $request
*/
protected function onLoginFail(Request $request) protected function onLoginFail(Request $request)
{ {
} }

View File

@ -22,6 +22,9 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*/ */
class ResponseListener implements EventSubscriberInterface class ResponseListener implements EventSubscriberInterface
{ {
/**
* @param FilterResponseEvent $event
*/
public function onKernelResponse(FilterResponseEvent $event) public function onKernelResponse(FilterResponseEvent $event)
{ {
$request = $event->getRequest(); $request = $event->getRequest();
@ -32,6 +35,9 @@ class ResponseListener implements EventSubscriberInterface
} }
} }
/**
* {@inheritDoc}
*/
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return array(KernelEvents::RESPONSE => 'onKernelResponse'); return array(KernelEvents::RESPONSE => 'onKernelResponse');