Merge branch '4.2'

* 4.2:
  [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:
Nicolas Grekas 2018-12-06 11:37:20 +00:00
commit ee337dd761
11 changed files with 59 additions and 15 deletions

View File

@ -28,7 +28,7 @@
"psr/link": "^1.0",
"psr/log": "~1.0",
"psr/simple-cache": "^1.0",
"symfony/contracts": "^1.0",
"symfony/contracts": "^1.0.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/polyfill-mbstring": "~1.0",

View File

@ -105,6 +105,7 @@ class FileType extends AbstractType
'data_class' => $dataClass,
'empty_data' => $emptyData,
'multiple' => false,
'allow_file_upload' => true,
));
}

View File

@ -180,6 +180,7 @@ class FormType extends BaseType
'attr' => array(),
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
'upload_max_size_message' => $uploadMaxSizeMessage, // internal
'allow_file_upload' => false,
'help' => null,
'help_attr' => array(),
));

View File

@ -532,6 +532,11 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
$submittedData = null;
} elseif (is_scalar($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();
@ -541,6 +546,10 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
$viewData = null;
try {
if (null !== $this->transformationFailure) {
throw $this->transformationFailure;
}
// Hook to change content of the data submitted by the browser
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
$event = new FormEvent($this, $submittedData);

View File

@ -709,7 +709,7 @@ class CompoundFormTest extends AbstractFormTest
'REQUEST_METHOD' => $method,
));
$form = $this->getBuilder('image')
$form = $this->getBuilder('image', null, null, array('allow_file_upload' => true))
->setMethod($method)
->setRequestHandler(new HttpFoundationRequestHandler())
->getForm();
@ -1081,6 +1081,21 @@ class CompoundFormTest extends AbstractFormTest
$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', 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()
{
return $this->getBuilder()

View File

@ -28,6 +28,7 @@
"parent": {
"Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType": [
"action",
"allow_file_upload",
"attr",
"auto_initialize",
"block_name",

View File

@ -8,15 +8,16 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
choice_attr FormType FormType FormTypeCsrfExtension
choice_label -------------------- ------------------------- -----------------------
choice_loader compound action csrf_field_name
choice_name data_class attr csrf_message
choice_translation_domain empty_data auto_initialize csrf_protection
choice_value error_bubbling block_name csrf_token_id
choices trim by_reference csrf_token_manager
expanded data
group_by disabled
multiple help
placeholder help_attr
preferred_choices inherit_data
choice_name data_class allow_file_upload csrf_message
choice_translation_domain empty_data attr csrf_protection
choice_value error_bubbling auto_initialize csrf_token_id
choices trim block_name csrf_token_manager
expanded by_reference
group_by data
multiple disabled
placeholder help
preferred_choices help_attr
inherit_data
label
label_attr
label_format

View File

@ -4,6 +4,7 @@
"options": {
"own": [
"action",
"allow_file_upload",
"attr",
"auto_initialize",
"block_name",

View File

@ -6,6 +6,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
Options
-------------------------
action
allow_file_upload
attr
auto_initialize
block_name

View File

@ -62,10 +62,10 @@ class HttpUtils
*/
public function createRedirectResponse(Request $request, $path, $status = 302)
{
if (null !== $this->secureDomainRegexp && 'https' === $this->urlMatcher->getContext()->getScheme() && preg_match('#^https?://[^/]++#i', $path, $host) && !preg_match(sprintf($this->secureDomainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
if (null !== $this->secureDomainRegexp && 'https' === $this->urlMatcher->getContext()->getScheme() && preg_match('#^https?:[/\\\\]{2,}+[^/]++#i', $path, $host) && !preg_match(sprintf($this->secureDomainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
$path = '/';
}
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 = '/';
}

View File

@ -54,14 +54,28 @@ class HttpUtilsTest extends TestCase
$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');
$response = $utils->createRedirectResponse($this->getRequest(), 'http://pirate.net/foo');
$response = $utils->createRedirectResponse($this->getRequest(), $url);
$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()
{
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');