Merge branch '2.8' into 3.4
* 2.8: [Security\Http] detect bad redirect targets using backslashes [Form] Filter file uploads out of regular form types Fix CI minor #28258 [travis] fix composer.lock invalidation for deps=low (nicolas-grekas) [travis] fix composer.lock invalidation for PRs patching several components [travis] fix composer.lock invalidation for deps=low minor #28199 [travis][appveyor] use symfony/flex to accelerate builds (nicolas-grekas) [travis] ignore ordering when validating composer.lock files for deps=low minor #28146 [travis] cache composer.lock files for deps=low (nicolas-grekas) fix ci [travis] fix requiring mongodb/mongodb before composer up minor #28114 [travis] merge "same Symfony version" jobs in one (nicolas-grekas) [2.7] Make CI green updated VERSION for 2.7.49 updated CHANGELOG for 2.7.49 [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer [HttpFoundation] Remove support for legacy and risky HTTP headers updated VERSION for 2.7.48 update CONTRIBUTORS for 2.7.48 updated CHANGELOG for 2.7.48
This commit is contained in:
commit
3aaa5aba1b
@ -105,6 +105,7 @@ class FileType extends AbstractType
|
|||||||
'data_class' => $dataClass,
|
'data_class' => $dataClass,
|
||||||
'empty_data' => $emptyData,
|
'empty_data' => $emptyData,
|
||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
|
'allow_file_upload' => true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +178,7 @@ class FormType extends BaseType
|
|||||||
'attr' => array(),
|
'attr' => array(),
|
||||||
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
|
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
|
||||||
'upload_max_size_message' => $uploadMaxSizeMessage, // internal
|
'upload_max_size_message' => $uploadMaxSizeMessage, // internal
|
||||||
|
'allow_file_upload' => false,
|
||||||
));
|
));
|
||||||
|
|
||||||
$resolver->setAllowedTypes('label_attr', 'array');
|
$resolver->setAllowedTypes('label_attr', 'array');
|
||||||
|
@ -532,6 +532,11 @@ class Form implements \IteratorAggregate, FormInterface
|
|||||||
$submittedData = null;
|
$submittedData = null;
|
||||||
} elseif (is_scalar($submittedData)) {
|
} elseif (is_scalar($submittedData)) {
|
||||||
$submittedData = (string) $submittedData;
|
$submittedData = (string) $submittedData;
|
||||||
|
} elseif ($this->config->getOption('allow_file_upload')) {
|
||||||
|
// no-op
|
||||||
|
} elseif ($this->config->getRequestHandler()->isFileUpload($submittedData)) {
|
||||||
|
$submittedData = null;
|
||||||
|
$this->transformationFailure = new TransformationFailedException('Submitted data was expected to be text or number, file upload given.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$dispatcher = $this->config->getEventDispatcher();
|
$dispatcher = $this->config->getEventDispatcher();
|
||||||
@ -541,6 +546,10 @@ class Form implements \IteratorAggregate, FormInterface
|
|||||||
$viewData = null;
|
$viewData = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (null !== $this->transformationFailure) {
|
||||||
|
throw $this->transformationFailure;
|
||||||
|
}
|
||||||
|
|
||||||
// Hook to change content of the data submitted by the browser
|
// Hook to change content of the data submitted by the browser
|
||||||
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
|
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
|
||||||
$event = new FormEvent($this, $submittedData);
|
$event = new FormEvent($this, $submittedData);
|
||||||
|
@ -707,7 +707,7 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
'REQUEST_METHOD' => $method,
|
'REQUEST_METHOD' => $method,
|
||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('image')
|
$form = $this->getBuilder('image', null, null, array('allow_file_upload' => true))
|
||||||
->setMethod($method)
|
->setMethod($method)
|
||||||
->setRequestHandler(new HttpFoundationRequestHandler())
|
->setRequestHandler(new HttpFoundationRequestHandler())
|
||||||
->getForm();
|
->getForm();
|
||||||
@ -1036,6 +1036,21 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
$this->assertFalse($submit->isSubmitted());
|
$this->assertFalse($submit->isSubmitted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFileUpload()
|
||||||
|
{
|
||||||
|
$reqHandler = new HttpFoundationRequestHandler();
|
||||||
|
$this->form->add($this->getBuilder('foo')->setRequestHandler($reqHandler)->getForm());
|
||||||
|
$this->form->add($this->getBuilder('bar')->setRequestHandler($reqHandler)->getForm());
|
||||||
|
|
||||||
|
$this->form->submit(array(
|
||||||
|
'foo' => 'Foo',
|
||||||
|
'bar' => new UploadedFile(__FILE__, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertSame('Submitted data was expected to be text or number, file upload given.', $this->form->get('bar')->getTransformationFailure()->getMessage());
|
||||||
|
$this->assertNull($this->form->get('bar')->getData());
|
||||||
|
}
|
||||||
|
|
||||||
protected function createForm()
|
protected function createForm()
|
||||||
{
|
{
|
||||||
return $this->getBuilder()
|
return $this->getBuilder()
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"parent": {
|
"parent": {
|
||||||
"Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType": [
|
"Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType": [
|
||||||
"action",
|
"action",
|
||||||
|
"allow_file_upload",
|
||||||
"attr",
|
"attr",
|
||||||
"auto_initialize",
|
"auto_initialize",
|
||||||
"block_name",
|
"block_name",
|
||||||
|
@ -8,16 +8,17 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
|
|||||||
choice_attr FormType FormType FormTypeCsrfExtension
|
choice_attr FormType FormType FormTypeCsrfExtension
|
||||||
choice_label -------------------- ------------------------- -----------------------
|
choice_label -------------------- ------------------------- -----------------------
|
||||||
choice_loader compound action csrf_field_name
|
choice_loader compound action csrf_field_name
|
||||||
choice_name data_class attr csrf_message
|
choice_name data_class allow_file_upload csrf_message
|
||||||
choice_translation_domain empty_data auto_initialize csrf_protection
|
choice_translation_domain empty_data attr csrf_protection
|
||||||
choice_value error_bubbling block_name csrf_token_id
|
choice_value error_bubbling auto_initialize csrf_token_id
|
||||||
choices trim by_reference csrf_token_manager
|
choices trim block_name csrf_token_manager
|
||||||
choices_as_values data
|
choices_as_values by_reference
|
||||||
expanded disabled
|
expanded data
|
||||||
group_by inherit_data
|
group_by disabled
|
||||||
multiple label
|
multiple inherit_data
|
||||||
placeholder label_attr
|
placeholder label
|
||||||
preferred_choices label_format
|
preferred_choices label_attr
|
||||||
|
label_format
|
||||||
mapped
|
mapped
|
||||||
method
|
method
|
||||||
post_max_size_message
|
post_max_size_message
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"own": [
|
"own": [
|
||||||
"action",
|
"action",
|
||||||
|
"allow_file_upload",
|
||||||
"attr",
|
"attr",
|
||||||
"auto_initialize",
|
"auto_initialize",
|
||||||
"block_name",
|
"block_name",
|
||||||
|
@ -6,6 +6,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
|
|||||||
Options
|
Options
|
||||||
-------------------------
|
-------------------------
|
||||||
action
|
action
|
||||||
|
allow_file_upload
|
||||||
attr
|
attr
|
||||||
auto_initialize
|
auto_initialize
|
||||||
block_name
|
block_name
|
||||||
|
@ -59,7 +59,7 @@ class HttpUtils
|
|||||||
*/
|
*/
|
||||||
public function createRedirectResponse(Request $request, $path, $status = 302)
|
public function createRedirectResponse(Request $request, $path, $status = 302)
|
||||||
{
|
{
|
||||||
if (null !== $this->domainRegexp && preg_match('#^https?://[^/]++#i', $path, $host) && !preg_match(sprintf($this->domainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
|
if (null !== $this->domainRegexp && preg_match('#^https?:[/\\\\]{2,}+[^/]++#i', $path, $host) && !preg_match(sprintf($this->domainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
|
||||||
$path = '/';
|
$path = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,14 +54,28 @@ class HttpUtilsTest extends TestCase
|
|||||||
$this->assertTrue($response->isRedirect('http://localhost/blog'));
|
$this->assertTrue($response->isRedirect('http://localhost/blog'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateRedirectResponseWithBadRequestsDomain()
|
/**
|
||||||
|
* @dataProvider badRequestDomainUrls
|
||||||
|
*/
|
||||||
|
public function testCreateRedirectResponseWithBadRequestsDomain($url)
|
||||||
{
|
{
|
||||||
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');
|
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');
|
||||||
$response = $utils->createRedirectResponse($this->getRequest(), 'http://pirate.net/foo');
|
$response = $utils->createRedirectResponse($this->getRequest(), $url);
|
||||||
|
|
||||||
$this->assertTrue($response->isRedirect('http://localhost/'));
|
$this->assertTrue($response->isRedirect('http://localhost/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function badRequestDomainUrls()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('http://pirate.net/foo'),
|
||||||
|
array('http:\\\\pirate.net/foo'),
|
||||||
|
array('http:/\\pirate.net/foo'),
|
||||||
|
array('http:\\/pirate.net/foo'),
|
||||||
|
array('http://////pirate.net/foo'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreateRedirectResponseWithProtocolRelativeTarget()
|
public function testCreateRedirectResponseWithProtocolRelativeTarget()
|
||||||
{
|
{
|
||||||
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');
|
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');
|
||||||
|
Reference in New Issue
Block a user