merged branch flojon/patch-3 (PR #5984)

This PR was merged into the 2.0 branch.

Commits
-------

64b54dc Use better default ports in urlRedirectAction
64216f2 Add tests for urlRedirectAction

Discussion
----------

Default to current port in urlRedirectAction

I was a bit surprised when I used urlRedirectAction from a non-standard port (8000) it redirected me to port 80. I would argue that the default should be to use the current port instead. This is a simple patch to change that. This should only break in the case someone is relying on the current default to redirect from a non-standard port to the standard port, which should be a really rare case...

---------------------------------------------------------------------------

by Tobion at 2012-11-11T20:29:54Z

The idea is right but the implementation not. Seems this patch is not as "simple" as you said.
When you're on HTTPS and want to redirect to $scheme = HTTP, then it still uses the current HTTPS port which is wrong.

---------------------------------------------------------------------------

by flojon at 2012-11-11T20:36:47Z

Ah, I see the problem. So I guess the correct behavior would be to use the current port if staying with the same scheme or go to standard port if switching scheme. Unless the user has specified a port which will always override...

---------------------------------------------------------------------------

by Tobion at 2012-11-11T20:42:18Z

That would be the best solution that is currently possible but not the best solution that should be possible.
Because if you switch scheme but the other scheme does not use the standard port, it still doesn't work.
Ideally the Request class had an option that allows to define the ports symfony should use for HTTP and HTTPS.
This logic is in RequestContext, but it's not used here.

---------------------------------------------------------------------------

by flojon at 2012-11-11T21:32:55Z

Bummer, I forgot to check if the current port is a standard port...

---------------------------------------------------------------------------

by Tobion at 2012-11-11T21:35:13Z

add some tests

---------------------------------------------------------------------------

by flojon at 2012-11-11T23:28:18Z

Added tests and fixed my previous error

---------------------------------------------------------------------------

by flojon at 2012-11-15T18:25:12Z

@Tobion is there anything else I needed for this?

---------------------------------------------------------------------------

by fabpot at 2012-11-19T12:56:04Z

To be consistent with how we manage HTTP ports elsewhere, I'd rather use the values of the `request_listener.http_port` and `request_listener.https_port`:

```php
        if (null === $httpPort) {
            $httpPort = $this->container->getParameter('request_listener.http_port');
        }

        if (null === $httpsPort) {
            $httpsPort = $this->container->getParameter('request_listener.https_port');
        }
```

This is done in the `security.authentication.retry_entry_point` service and for the `router_listener` listener.

The parameter name is probably not the best one, but that could be changed then in master.

---------------------------------------------------------------------------

by flojon at 2012-11-19T13:49:18Z

@fabpot But then you would need to set that parameter manually right? It wouldn't automatically redirect you to the same port, which was what I wanted to achieve...

Could this be the right order of preference:
If a value was specified in the route use that.
Otherwise use the current port
unless switching scheme then use the parameter value

---------------------------------------------------------------------------

by fabpot at 2012-11-19T13:52:17Z

Your order of preference looks good to me.

---------------------------------------------------------------------------

by flojon at 2012-11-19T19:13:19Z

Man this was more involved than I thought... :)
Changed the logic to use the parameters when not using the current port. Also tried clean up the tests a little bit... Enjoy!
This commit is contained in:
Fabien Potencier 2012-11-19 20:59:22 +01:00
commit ebd5e9286c
2 changed files with 150 additions and 5 deletions

View File

@ -64,7 +64,7 @@ class RedirectController extends ContainerAware
*
* @return Response A Response instance
*/
public function urlRedirectAction($path, $permanent = false, $scheme = null, $httpPort = 80, $httpsPort = 443)
public function urlRedirectAction($path, $permanent = false, $scheme = null, $httpPort = null, $httpsPort = null)
{
if (!$path) {
return new Response(null, 410);
@ -88,10 +88,28 @@ class RedirectController extends ContainerAware
}
$port = '';
if ('http' === $scheme && 80 != $httpPort) {
$port = ':'.$httpPort;
} elseif ('https' === $scheme && 443 != $httpsPort) {
$port = ':'.$httpsPort;
if ('http' === $scheme) {
if ($httpPort == null) {
if ('http' === $request->getScheme()) {
$httpPort = $request->getPort();
} else {
$httpPort = $this->container->getParameter('request_listener.http_port');
}
}
if ($httpPort != null && $httpPort != 80) {
$port = ":$httpPort";
}
} else if ('https' === $scheme) {
if ($httpsPort == null) {
if ('https' === $request->getScheme()) {
$httpsPort = $request->getPort();
} else {
$httpsPort = $this->container->getParameter('request_listener.https_port');
}
}
if ($httpsPort != null && $httpsPort != 443) {
$port = ":$httpsPort";
}
}
$url = $scheme.'://'.$request->getHost().$port.$request->getBaseUrl().$path.$qs;

View File

@ -109,4 +109,131 @@ class RedirectControllerTest extends TestCase
$this->assertEquals('http://foo.bar/', $returnResponse->headers->get('Location'));
$this->assertEquals(302, $returnResponse->getStatusCode());
}
public function testUrlRedirectDefaultPortParameters()
{
$host = 'www.example.com';
$baseUrl = '/base';
$path = '/redirect-path';
$httpPort = 1080;
$httpsPort = 1443;
$expectedUrl = "https://$host:$httpsPort$baseUrl$path";
$request = $this->createRequestObject('http', $host, $httpPort, $baseUrl);
$controller = $this->createRedirectController($request, null, $httpsPort);
$returnValue = $controller->urlRedirectAction($path, false, 'https');
$this->assertRedirectUrl($returnValue, $expectedUrl);
$expectedUrl = "http://$host:$httpPort$baseUrl$path";
$request = $this->createRequestObject('https', $host, $httpPort, $baseUrl);
$controller = $this->createRedirectController($request, $httpPort);
$returnValue = $controller->urlRedirectAction($path, false, 'http');
$this->assertRedirectUrl($returnValue, $expectedUrl);
}
public function urlRedirectProvider()
{
return array(
// Standard ports
array('http', null, null, 'http', 80, ""),
array('http', 80, null, 'http', 80, ""),
array('https', null, null, 'http', 80, ""),
array('https', 80, null, 'http', 80, ""),
array('http', null, null, 'https', 443, ""),
array('http', null, 443, 'https', 443, ""),
array('https', null, null, 'https', 443, ""),
array('https', null, 443, 'https', 443, ""),
// Non-standard ports
array('http', null, null, 'http', 8080, ":8080"),
array('http', 4080, null, 'http', 8080, ":4080"),
array('http', 80, null, 'http', 8080, ""),
array('https', null, null, 'http', 8080, ""),
array('https', null, 8443, 'http', 8080, ":8443"),
array('https', null, 443, 'http', 8080, ""),
array('https', null, null, 'https', 8443, ":8443"),
array('https', null, 4443, 'https', 8443, ":4443"),
array('https', null, 443, 'https', 8443, ""),
array('http', null, null, 'https', 8443, ""),
array('http', 8080, 4443, 'https', 8443, ":8080"),
array('http', 80, 4443, 'https', 8443, ""),
);
}
/**
* @dataProvider urlRedirectProvider
*/
public function testUrlRedirect($scheme, $httpPort, $httpsPort, $requestScheme, $requestPort, $expectedPort)
{
$host = 'www.example.com';
$baseUrl = '/base';
$path = '/redirect-path';
$expectedUrl = "$scheme://$host$expectedPort$baseUrl$path";
$request = $this->createRequestObject($requestScheme, $host, $requestPort, $baseUrl);
$controller = $this->createRedirectController($request);
$returnValue = $controller->urlRedirectAction($path, false, $scheme, $httpPort, $httpsPort);
$this->assertRedirectUrl($returnValue, $expectedUrl);
}
public function createRequestObject($scheme, $host, $port, $baseUrl)
{
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$request
->expects($this->any())
->method('getScheme')
->will($this->returnValue($scheme));
$request
->expects($this->any())
->method('getHost')
->will($this->returnValue($host));
$request
->expects($this->any())
->method('getPort')
->will($this->returnValue($port));
$request
->expects($this->any())
->method('getBaseUrl')
->will($this->returnValue($baseUrl));
return $request;
}
public function createRedirectController($request, $httpPort = null, $httpsPort = null)
{
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container
->expects($this->at(0))
->method('get')
->with($this->equalTo('request'))
->will($this->returnValue($request));
if ($httpPort != null) {
$container
->expects($this->at(1))
->method('getParameter')
->with($this->equalTo('request_listener.http_port'))
->will($this->returnValue($httpPort));
}
if ($httpsPort != null) {
$container
->expects($this->at(1))
->method('getParameter')
->with($this->equalTo('request_listener.https_port'))
->will($this->returnValue($httpsPort));
}
$controller = new RedirectController();
$controller->setContainer($container);
return $controller;
}
public function assertRedirectUrl($returnValue, $expectedUrl)
{
$this->assertTrue($returnValue->isRedirect($expectedUrl),
"Expected: $expectedUrl\nGot: " . $returnValue->headers->get('Location'));
}
}