feature #23076 [Validator] Adds support to check specific DNS record type for URL (iisisrael)

This PR was merged into the 3.4 branch.

Discussion
----------

[Validator] Adds support to check specific DNS record type for URL

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

URL validation with the `checkDNS` option can time out for some international registrars or for reasons unknown.  When the `URL` constraint is implemented, the context may logically allow for a single DNS record type to be checked, which is less prone to timing out.  This updates the `checkDNS` option value to be one of any valid for the underlying `checkdnsrr()` method with backwards compatibility for the original boolean value.

Commits
-------

e66d8f1bef [Validator] Adds support to check specific DNS record type for URL
This commit is contained in:
Fabien Potencier 2017-06-15 07:35:35 -07:00
commit 1f6330a9b9
4 changed files with 111 additions and 3 deletions

View File

@ -6,6 +6,7 @@ CHANGELOG
* not setting the `strict` option of the `Choice` constraint to `true` is
deprecated and will throw an exception in Symfony 4.0
* setting the `checkDNS` option of the `Url` constraint to `true` is deprecated in favor of constant values and will throw an exception in Symfony 4.0
3.3.0
-----

View File

@ -21,6 +21,20 @@ use Symfony\Component\Validator\Constraint;
*/
class Url extends Constraint
{
const CHECK_DNS_TYPE_ANY = 'ANY';
const CHECK_DNS_TYPE_NONE = false;
const CHECK_DNS_TYPE_A = 'A';
const CHECK_DNS_TYPE_A6 = 'A6';
const CHECK_DNS_TYPE_AAAA = 'AAAA';
const CHECK_DNS_TYPE_CNAME = 'CNAME';
const CHECK_DNS_TYPE_MX = 'MX';
const CHECK_DNS_TYPE_NAPTR = 'NAPTR';
const CHECK_DNS_TYPE_NS = 'NS';
const CHECK_DNS_TYPE_PTR = 'PTR';
const CHECK_DNS_TYPE_SOA = 'SOA';
const CHECK_DNS_TYPE_SRV = 'SRV';
const CHECK_DNS_TYPE_TXT = 'TXT';
const INVALID_URL_ERROR = '57c2f299-1154-4870-89bb-ef3b1f5ad229';
protected static $errorNames = array(
@ -30,5 +44,5 @@ class Url extends Constraint
public $message = 'This value is not a valid URL.';
public $dnsMessage = 'The host could not be resolved.';
public $protocols = array('http', 'https');
public $checkDNS = false;
public $checkDNS = self::CHECK_DNS_TYPE_NONE;
}

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\InvalidOptionsException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
@ -72,9 +73,32 @@ class UrlValidator extends ConstraintValidator
}
if ($constraint->checkDNS) {
// backwards compatibility
if ($constraint->checkDNS === true) {
$constraint->checkDNS = Url::CHECK_DNS_TYPE_ANY;
@trigger_error(sprintf('Use of the boolean TRUE for the "checkDNS" option in %s is deprecated. Use Url::CHECK_DNS_TYPE_ANY instead.', Url::class), E_USER_DEPRECATED);
}
if (!in_array($constraint->checkDNS, array(
Url::CHECK_DNS_TYPE_ANY,
Url::CHECK_DNS_TYPE_A,
Url::CHECK_DNS_TYPE_A6,
Url::CHECK_DNS_TYPE_AAAA,
Url::CHECK_DNS_TYPE_CNAME,
Url::CHECK_DNS_TYPE_MX,
Url::CHECK_DNS_TYPE_NAPTR,
Url::CHECK_DNS_TYPE_NS,
Url::CHECK_DNS_TYPE_PTR,
Url::CHECK_DNS_TYPE_SOA,
Url::CHECK_DNS_TYPE_SRV,
Url::CHECK_DNS_TYPE_TXT,
))) {
throw new InvalidOptionsException(sprintf('Invalid value for option "checkDNS" in constraint %s', get_class($constraint)), array('checkDNS'));
}
$host = parse_url($value, PHP_URL_HOST);
if (!is_string($host) || !checkdnsrr($host, 'ANY')) {
if (!is_string($host) || !checkdnsrr($host, $constraint->checkDNS)) {
$this->context->buildViolation($constraint->dnsMessage)
->setParameter('{{ value }}', $this->formatValue($host))
->setCode(Url::INVALID_URL_ERROR)

View File

@ -203,7 +203,7 @@ class UrlValidatorTest extends ConstraintValidatorTestCase
DnsMock::withMockedHosts(array('example.com' => array(array('type' => $violation ? '' : 'A'))));
$constraint = new Url(array(
'checkDNS' => true,
'checkDNS' => 'ANY',
'dnsMessage' => 'myMessage',
));
@ -223,6 +223,75 @@ class UrlValidatorTest extends ConstraintValidatorTestCase
{
return array(array(true), array(false));
}
/**
* @dataProvider getCheckDnsTypes
* @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts
*/
public function testCheckDnsByType($type)
{
DnsMock::withMockedHosts(array('example.com' => array(array('type' => $type))));
$constraint = new Url(array(
'checkDNS' => $type,
'dnsMessage' => 'myMessage',
));
$this->validator->validate('http://example.com', $constraint);
$this->assertNoViolation();
}
public function getCheckDnsTypes()
{
return array(
array('ANY'),
array('A'),
array('A6'),
array('AAAA'),
array('CNAME'),
array('MX'),
array('NAPTR'),
array('NS'),
array('PTR'),
array('SOA'),
array('SRV'),
array('TXT'),
);
}
/**
* @group legacy
*/
public function testCheckDnsWithBoolean()
{
DnsMock::withMockedHosts(array('example.com' => array(array('type' => 'A'))));
$constraint = new Url(array(
'checkDNS' => true,
'dnsMessage' => 'myMessage',
));
$this->validator->validate('http://example.com', $constraint);
$this->assertNoViolation();
}
/**
* @expectedException \Symfony\Component\Validator\Exception\InvalidOptionsException
* @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts
*/
public function testCheckDnsWithInvalidType()
{
DnsMock::withMockedHosts(array('example.com' => array(array('type' => 'A'))));
$constraint = new Url(array(
'checkDNS' => 'BOGUS',
'dnsMessage' => 'myMessage',
));
$this->validator->validate('http://example.com', $constraint);
}
}
class EmailProvider