Merge branch '2.2'

* 2.2: (22 commits)
  [Process] Fix regression introduced in #6620 / 880da01c49, fixes #7082
  [HttpKernel] added a unit for the previous commit (closes #7025)
  [HttpFoundation] fixed, overwritten CONTENT_TYPE
  [BrowserKit] fixed test added in the previous merge (refs #7059)
  [FrameworkBundle] tweaked reference dumper command (see #7093)
  Remove unnecessary comment and change test name
  [Config] tweaked dumper to indent multi-line info
  [HttpKernel] added some tests for previous merge
  Fix REMOTE_ADDR for cached subrequests
  [FrameworkBundle] CSRF should be on by default
  [WebProfilerBundle] removed dependency on FrameworkBundle (closes #6949)
  [HttpKernel] added error display suppression when using the ErrorHandler (if not, errors are displayed twice, refs #6254)
  [HttpFoundation] tweaked previous merge
  [HttpFoundation] Added getter for httpMethodParameterOverride state
  Create validators.lv.xlf
  [Process] Warn user with a useful message when tmpfile() failed
  [BrowserKit] added a test to make sure HTTP authentication is preserved when submitting a form
  Remove array type hint from GetResponseForControllerResultEvent::setControllerResult()
  bumped Symfony version to 2.2.0-DEV
  Revert "merged branch povilas/issue_6101 (PR #6708)"
  ...
This commit is contained in:
Fabien Potencier 2013-02-18 22:28:20 +01:00
commit 1c783f6038
26 changed files with 292 additions and 56 deletions

View File

@ -94,7 +94,7 @@ class Configuration implements ConfigurationInterface
->canBeEnabled()
->end()
->arrayNode('csrf_protection')
->canBeEnabled()
->canBeDisabled()
->children()
->scalarNode('field_name')->defaultValue('_token')->end()
->end()

View File

@ -41,7 +41,7 @@ class ContainerAwareHIncludeFragmentRenderer extends HIncludeFragmentRenderer
public function render($uri, Request $request, array $options = array())
{
if (!$this->templating) {
$this->templating = $this->container->get('templating');
$this->setTemplating($this->container->get('templating'));
}
return parent::render($uri, $request, $options);

View File

@ -94,7 +94,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
'default_locale' => 'en',
'form' => array('enabled' => false),
'csrf_protection' => array(
'enabled' => false,
'enabled' => true,
'field_name' => '_token',
),
'esi' => array('enabled' => false),

View File

@ -0,0 +1,6 @@
framework:
secret: s3cr3t
form: ~
session: ~
# CSRF should be enabled by default
# csrf_protection: ~

View File

@ -22,4 +22,11 @@ class YamlFrameworkExtensionTest extends FrameworkExtensionTest
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/Fixtures/yml'));
$loader->load($file.'.yml');
}
public function testCsrfProtectionShouldBeEnabledByDefault()
{
$container = $this->createContainerFromFile('csrf');
$this->assertTrue($container->getParameter('form.type_extension.csrf.enabled'));
}
}

View File

@ -52,6 +52,18 @@ class ProfilerController
$this->toolbarPosition = $toolbarPosition;
}
/**
* Redirects to the last profiles.
*
* @return RedirectResponse A RedirectResponse instance
*/
public function homeAction()
{
$this->profiler->disable();
return new RedirectResponse($this->generator->generate('_profiler_search_results', array('token' => 'empty', 'limit' => 10)));
}
/**
* Renders a profiler panel for the given token.
*

View File

@ -4,6 +4,10 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="_profiler_home" pattern="/">
<default key="_controller">web_profiler.controller.profiler:homeAction</default>
</route>
<route id="_profiler_search" pattern="/search">
<default key="_controller">web_profiler.controller.profiler:searchAction</default>
</route>
@ -52,14 +56,4 @@
<default key="_controller">web_profiler.controller.exception:cssAction</default>
</route>
<route id="_profiler_redirect" pattern="/">
<default key="_controller">FrameworkBundle:Redirect:redirect</default>
<default key="route">_profiler_search_results</default>
<default key="token">empty</default>
<default key="ip"></default>
<default key="url"></default>
<default key="method"></default>
<default key="limit">10</default>
</route>
</routes>

View File

@ -262,6 +262,37 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->submit() submit forms');
}
public function testSubmitPreserveAuth()
{
if (!class_exists('Symfony\Component\DomCrawler\Crawler')) {
$this->markTestSkipped('The "DomCrawler" component is not available');
}
if (!class_exists('Symfony\Component\CssSelector\CssSelector')) {
$this->markTestSkipped('The "CssSelector" component is not available');
}
$client = new TestClient(array('PHP_AUTH_USER' => 'foo', 'PHP_AUTH_PW' => 'bar'));
$client->setNextResponse(new Response('<html><form action="/foo"><input type="submit" /></form></html>'));
$crawler = $client->request('GET', 'http://www.example.com/foo/foobar');
$server = $client->getRequest()->getServer();
$this->assertArrayHasKey('PHP_AUTH_USER', $server);
$this->assertEquals('foo', $server['PHP_AUTH_USER']);
$this->assertArrayHasKey('PHP_AUTH_PW', $server);
$this->assertEquals('bar', $server['PHP_AUTH_PW']);
$client->submit($crawler->filter('input')->form());
$this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->submit() submit forms');
$server = $client->getRequest()->getServer();
$this->assertArrayHasKey('PHP_AUTH_USER', $server);
$this->assertEquals('foo', $server['PHP_AUTH_USER']);
$this->assertArrayHasKey('PHP_AUTH_PW', $server);
$this->assertEquals('bar', $server['PHP_AUTH_PW']);
}
public function testFollowRedirect()
{
$client = new TestClient();

View File

@ -115,10 +115,12 @@ class ReferenceDumper
$default = (string) $default != '' ? ' '.$default : '';
$comments = count($comments) ? '# '.implode(', ', $comments) : '';
$text = sprintf('%-20s %s %s', $node->getName().':', $default, $comments);
$text = rtrim(sprintf('%-20s %s %s', $node->getName() . ':', $default, $comments), ' ');
if ($info = $node->getInfo()) {
$this->writeLine('');
// indenting multi-line info
$info = str_replace("\n", sprintf("\n%" . $depth * 4 . "s# ", ' '), $info);
$this->writeLine('# '.$info, $depth * 4);
}

View File

@ -0,0 +1,62 @@
<?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\Config\Tests\Definition;
use Symfony\Component\Config\Definition\ReferenceDumper;
use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration;
class ReferenceDumperTest extends \PHPUnit_Framework_TestCase
{
public function testDumper()
{
$configuration = new ExampleConfiguration();
$dumper = new ReferenceDumper();
$this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration));
}
private function getConfigurationAsString()
{
return <<<EOL
root:
boolean: true
scalar_empty: ~
scalar_null: ~
scalar_true: true
scalar_false: false
scalar_default: default
scalar_array_empty: []
scalar_array_defaults:
# Defaults:
- elem1
- elem2
# some info
array:
child1: ~
child2: ~
# this is a long
# multi-line info text
# which should be indented
child3: ~ # Example: example setting
array_prototype:
parameters:
# Prototype
name:
value: ~ # Required
EOL;
}
}

View File

@ -0,0 +1,67 @@
<?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\Config\Tests\Fixtures\Configuration;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class ExampleConfiguration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('root');
$rootNode
->children()
->booleanNode('boolean')->defaultTrue()->end()
->scalarNode('scalar_empty')->end()
->scalarNode('scalar_null')->defaultNull()->end()
->scalarNode('scalar_true')->defaultTrue()->end()
->scalarNode('scalar_false')->defaultFalse()->end()
->scalarNode('scalar_default')->defaultValue('default')->end()
->scalarNode('scalar_array_empty')->defaultValue(array())->end()
->scalarNode('scalar_array_defaults')->defaultValue(array('elem1', 'elem2'))->end()
->arrayNode('array')
->info('some info')
->canBeUnset()
->children()
->scalarNode('child1')->end()
->scalarNode('child2')->end()
->scalarNode('child3')
->info(
"this is a long\n".
"multi-line info text\n".
"which should be indented"
)
->example('example setting')
->end()
->end()
->end()
->arrayNode('array_prototype')
->children()
->arrayNode('parameters')
->useAttributeAsKey('name')
->prototype('array')
->children()
->scalarNode('value')->isRequired()->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
return $treeBuilder;
}
}

View File

@ -1,13 +1,16 @@
<?php
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$container = new ContainerBuilder();
$container->
register('foo', 'FooClass')->
addArgument(new Reference('bar'))
;
$container->
register('bar', 'BarClass')
;
$container->compile();
return $container;

View File

@ -4,5 +4,7 @@ digraph sc {
edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"];
node_foo [label="foo\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_bar [label="bar\nBarClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_foo -> node_bar [label="" style="filled"];
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="28">
<source>This form should not contain extra fields.</source>
<target>Šajā veidlapā nevajadzētu būt papildus ievades laukiem.</target>
</trans-unit>
<trans-unit id="29">
<source>The uploaded file was too large. Please try to upload a smaller file.</source>
<target>Augšupielādētā faila izmērs bija par lielu. Lūdzu mēģiniet augšupielādēt mazāka izmēra failu.</target>
</trans-unit>
<trans-unit id="30">
<source>The CSRF token is invalid. Please try to resubmit the form.</source>
<target>Dotais CSRF talons nav derīgs. Lūdzu mēģiniet vēlreiz iesniegt veidlapu.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -86,10 +86,7 @@ class ChoiceTypeTest extends TypeTestCase
));
}
/**
* expectedException \Symfony\Component\Form\Exception\Exception
*/
public function testEitherChoiceListOrChoicesMustBeSet()
public function testChoiceListAndChoicesCanBeEmpty()
{
$this->factory->create('choice', null, array(
));

View File

@ -22,7 +22,6 @@ use Symfony\Component\HttpFoundation\File\Exception\FileException;
* @author Igor Wiedler <igor@wiedler.ch>
* @author Jordan Alliot <jordan.alliot@gmail.com>
* @author Sergey Linnik <linniksa@gmail.com>
* @author Povilas Skruibis <puovils@gmail.com>
*/
class BinaryFileResponse extends Response
{
@ -124,23 +123,11 @@ class BinaryFileResponse extends Response
*/
public function setAutoEtag()
{
$this->setEtag($this->calculateFileHash($this->file->getPathname()));
$this->setEtag(sha1_file($this->file->getPathname()));
return $this;
}
/**
* Calculate file hash
*
* @param string $filename The path to the file
*
* @return string
*/
protected function calculateFileHash($filename)
{
return sha1_file($filename);
}
/**
* Sets the Content-Disposition header with the given filename.
*

View File

@ -10,7 +10,8 @@ CHANGELOG
* [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects
* added a IpUtils class to check if an IP belongs to a CIDR
* added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it)
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to
enable it, and Request::getHttpMethodParameterOverride() to check if it is supported)
* Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
* Deprecated Flashbag::count() and \Countable interface, will be removed in 2.3

View File

@ -325,7 +325,9 @@ class Request
case 'POST':
case 'PUT':
case 'DELETE':
$server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
if (!isset($server['CONTENT_TYPE'])) {
$server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
}
case 'PATCH':
$request = $parameters;
$query = array();
@ -594,6 +596,16 @@ class Request
self::$httpMethodParameterOverride = true;
}
/**
* Checks whether support for the _method request parameter is enabled.
*
* @return Boolean True when the _method request parameter is enabled, false otherwise
*/
public static function getHttpMethodParameterOverride()
{
return self::$httpMethodParameterOverride;
}
/**
* Gets a "parameter" value.
*

View File

@ -228,13 +228,14 @@ class RequestTest extends \PHPUnit_Framework_TestCase
public function testCreateCheckPrecedence()
{
// server is used by default
$request = Request::create('/', 'GET', array(), array(), array(), array(
$request = Request::create('/', 'DELETE', array(), array(), array(), array(
'HTTP_HOST' => 'example.com',
'HTTPS' => 'on',
'SERVER_PORT' => 443,
'PHP_AUTH_USER' => 'fabien',
'PHP_AUTH_PW' => 'pa$$',
'QUERY_STRING' => 'foo=bar',
'CONTENT_TYPE' => 'application/json',
));
$this->assertEquals('example.com', $request->getHost());
$this->assertEquals(443, $request->getPort());
@ -242,6 +243,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('fabien', $request->getUser());
$this->assertEquals('pa$$', $request->getPassword());
$this->assertEquals('', $request->getQueryString());
$this->assertEquals('application/json', $request->headers->get('CONTENT_TYPE'));
// URI has precedence over server
$request = Request::create('http://thomas:pokemon@example.net:8080/?foo=bar', 'GET', array(), array(), array(), array(
@ -712,7 +714,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$request = new Request();
$request->setMethod('POST');
$request->request->set('_method', 'purge');
$this->assertFalse(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be disabled by default');
Request::enableHttpMethodParameterOverride();
$this->assertTrue(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be enabled now but it is not');
$this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
$this->disableHttpMethodParameterOverride();

View File

@ -58,6 +58,7 @@ class ErrorHandler
$handler = new static();
$handler->setLevel($level);
ini_set('display_errors', 0);
set_error_handler(array($handler, 'handle'));
register_shutdown_function(array($handler, 'handleFatal'));
$handler->reservedMemory = str_repeat('x', 10240);

View File

@ -56,11 +56,11 @@ class GetResponseForControllerResultEvent extends GetResponseEvent
/**
* Assigns the return value of the controller.
*
* @param array The controller return value
* @param mixed The controller return value
*
* @api
*/
public function setControllerResult(array $controllerResult)
public function setControllerResult($controllerResult)
{
$this->controllerResult = $controllerResult;
}

View File

@ -24,10 +24,9 @@ use Symfony\Component\HttpKernel\UriSigner;
*/
class HIncludeFragmentRenderer extends RoutableFragmentRenderer
{
protected $templating;
private $globalDefaultTemplate;
private $signer;
private $templating;
/**
* Constructor.
@ -37,14 +36,24 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer
* @param string $globalDefaultTemplate The global default content (it can be a template name or the content)
*/
public function __construct($templating = null, UriSigner $signer = null, $globalDefaultTemplate = null)
{
$this->setTemplating($templating);
$this->globalDefaultTemplate = $globalDefaultTemplate;
$this->signer = $signer;
}
/**
* Sets the templating engine to use to render the default content.
*
* @param EngineInterface|\Twig_Environment|null $templating An EngineInterface or a \Twig_Environment instance
*/
public function setTemplating($templating)
{
if (null !== $templating && !$templating instanceof EngineInterface && !$templating instanceof \Twig_Environment) {
throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of \Twig_Environment or Symfony\Component\Templating\EngineInterface');
}
$this->templating = $templating;
$this->globalDefaultTemplate = $globalDefaultTemplate;
$this->signer = $signer;
}
/**

View File

@ -418,18 +418,6 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
$subRequest->headers->remove('if_modified_since');
$subRequest->headers->remove('if_none_match');
// modify the X-Forwarded-For header if needed
$forwardedFor = $subRequest->headers->get('X-Forwarded-For');
if ($forwardedFor) {
$subRequest->headers->set('X-Forwarded-For', $forwardedFor.', '.$subRequest->server->get('REMOTE_ADDR'));
} else {
$subRequest->headers->set('X-Forwarded-For', $subRequest->server->get('REMOTE_ADDR'));
}
// fix the client IP address by setting it to 127.0.0.1 as HttpCache
// is always called from the same process as the backend.
$subRequest->server->set('REMOTE_ADDR', '127.0.0.1');
$response = $this->forward($subRequest, $catch);
if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) {
@ -460,6 +448,18 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
$this->esi->addSurrogateEsiCapability($request);
}
// modify the X-Forwarded-For header if needed
$forwardedFor = $request->headers->get('X-Forwarded-For');
if ($forwardedFor) {
$request->headers->set('X-Forwarded-For', $forwardedFor.', '.$request->server->get('REMOTE_ADDR'));
} else {
$request->headers->set('X-Forwarded-For', $request->server->get('REMOTE_ADDR'));
}
// fix the client IP address by setting it to 127.0.0.1 as HttpCache
// is always called from the same process as the backend.
$request->server->set('REMOTE_ADDR', '127.0.0.1');
// always a "master" request (as the real master request can be in cache)
$response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch);
// FIXME: we probably need to also catch exceptions if raw === true

View File

@ -62,12 +62,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface
protected $classes;
protected $errorReportingLevel;
const VERSION = '2.2.0-RC2';
const VERSION = '2.2.0-DEV';
const VERSION_ID = '20100';
const MAJOR_VERSION = '2';
const MINOR_VERSION = '2';
const RELEASE_VERSION = '0';
const EXTRA_VERSION = 'RC2';
const EXTRA_VERSION = 'DEV';
/**
* Constructor.

View File

@ -1066,4 +1066,13 @@ class HttpCacheTest extends HttpCacheTestCase
array('10.0.0.2, 10.0.0.3', '10.0.0.2, 10.0.0.3, 10.0.0.1'),
);
}
public function testXForwarderForHeaderForPassRequests()
{
$this->setNextResponse();
$server = array('REMOTE_ADDR' => '10.0.0.1');
$this->request('POST', '/', $server);
$this->assertEquals('10.0.0.1', $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
}
}

View File

@ -131,6 +131,10 @@ class Process
$this->commandline = $commandline;
$this->cwd = $cwd;
// on windows, if the cwd changed via chdir(), proc_open defaults to the dir where php was started
if (null === $this->cwd && defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->cwd = getcwd();
}
if (null !== $env) {
$this->env = array();
foreach ($env as $key => $value) {
@ -232,6 +236,9 @@ class Process
$this->fileHandles = array(
self::STDOUT => tmpfile(),
);
if (false === $this->fileHandles[self::STDOUT]) {
throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');
}
$this->readBytes = array(
self::STDOUT => 0,
);