Skip to content

Commit

Permalink
feature #23076 [Validator] Adds support to check specific DNS record …
Browse files Browse the repository at this point in the history
…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
-------

e66d8f1 [Validator] Adds support to check specific DNS record type for URL
  • Loading branch information
fabpot committed Jun 15, 2017
2 parents bc4dd8f + e66d8f1 commit 1f6330a
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Component/Validator/CHANGELOG.md
Expand Up @@ -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
-----
Expand Down
16 changes: 15 additions & 1 deletion src/Symfony/Component/Validator/Constraints/Url.php
Expand Up @@ -21,6 +21,20 @@
*/
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(
Expand All @@ -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;
}
26 changes: 25 additions & 1 deletion src/Symfony/Component/Validator/Constraints/UrlValidator.php
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\InvalidOptionsException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

/**
Expand Down Expand Up @@ -72,9 +73,32 @@ public function validate($value, Constraint $constraint)
}

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)
Expand Down
Expand Up @@ -203,7 +203,7 @@ public function testCheckDns($violation)
DnsMock::withMockedHosts(array('example.com' => array(array('type' => $violation ? '' : 'A'))));

$constraint = new Url(array(
'checkDNS' => true,
'checkDNS' => 'ANY',
'dnsMessage' => 'myMessage',
));

Expand All @@ -223,6 +223,75 @@ public function getCheckDns()
{
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
Expand Down

0 comments on commit 1f6330a

Please sign in to comment.