From a7972b69f7d80e14daff8c9165f0d255d73280e0 Mon Sep 17 00:00:00 2001 From: Ignace Nyamagana Butera Date: Mon, 17 Apr 2017 22:01:50 +0200 Subject: [PATCH] bug fix issue #5 --- CHANGELOG.md | 18 ++++++++++++++++ src/Parser.php | 49 +++++++++++++++++++++++++++++--------------- tests/ParserTest.php | 7 +++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ed42a..2c3f10e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All Notable changes to `league-uri-parser` will be documented in this file +## Next + +### Added + +- None + +### Fixed + +- [issue #5](https://github.com/thephpleague/uri-parser/issues/5) Improve `Parser::isHost` validation of regsitered name + +### Deprecated + +- None + +### Removed + +- None + ## 1.0.4 - 2017-03-01 ### Added diff --git a/src/Parser.php b/src/Parser.php index 017fd04..8fbccec 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -323,6 +323,15 @@ protected function isIpv6Host(string $ipv6): bool /** * Returns whether the hostname is valid * + * A valid registered name MUST: + * + * - contains at most 127 subdomains deep + * - be limited to 255 octets in length + * + * @see https://en.wikipedia.org/wiki/Subdomain + * @see https://tools.ietf.org/html/rfc1035#section-2.3.4 + * @see https://blogs.msdn.microsoft.com/oldnewthing/20120412-00/?p=7873/ + * * @param string $host * * @return bool @@ -335,45 +344,53 @@ protected function isRegisteredName(string $host): bool $labels = array_map([$this, 'toAscii'], explode('.', $host)); - return 127 > count($labels) && $labels === array_filter($labels, [$this, 'isHostLabel']); + return 127 > count($labels) + && 253 > strlen(implode('.', $labels)) + && $labels === array_filter($labels, [$this, 'isHostLabel']); } /** - * Convert domain name to IDNA ASCII form. + * Convert a registered name label to its IDNA ASCII form. + * + * Conversion is done only if the label contains none valid label characters * * @param string $label * - * @return string + * @return string|false */ protected function toAscii(string $label) { - $res = idn_to_ascii($label, 0, INTL_IDNA_VARIANT_UTS46); - if (false !== $res) { - return $res; + if (strlen($label) === strspn($label, self::LABEL_VALID_STARTING_CHARS.'-')) { + return $label; } - return ''; + return idn_to_ascii($label, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); } - /** - * Returns whether the host label is valid + * Returns whether the registered name label is valid + * + * A valid registered name label MUST: + * + * - not be empty + * - contain 63 characters or less + * - contain alphanumeric ASCII character or a hyphen + * - start and end whith an alpha numeric ASCII character + * + * @see https://tools.ietf.org/html/rfc1034#section-3.5 * * @param string $label * * @return bool */ - protected function isHostLabel(string $label): bool + protected function isHostLabel($label): bool { - if ('' == $label) { + if (!is_string($label) || '' == $label || 63 < strlen($label)) { return false; } - $pos = strlen($label); - $delimiters = $label[0].$label[$pos - 1]; - - return 2 === strspn($delimiters, self::LABEL_VALID_STARTING_CHARS) - && $pos === strspn($label, self::LABEL_VALID_STARTING_CHARS.'-'); + return 2 === strspn($label[0].substr($label, -1, 1), self::LABEL_VALID_STARTING_CHARS) + && strlen($label) === strspn($label, self::LABEL_VALID_STARTING_CHARS.'-'); } /** diff --git a/tests/ParserTest.php b/tests/ParserTest.php index cacd525..6682b9f 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -682,6 +682,8 @@ public function testHost($host, $expected) public function validHostProvider() { + $long_label = implode('.', array_fill(0, 62, 'a')); + return [ 'RFC3986 registered name' => ['bebe.be', true], 'RFC3987 registered name' => ['bébé.bé', true], @@ -697,6 +699,11 @@ public function validHostProvider() 'invalid IPv6 host (6)' => ['[[::1]]', false], 'invalid IPv6 host (7)' => ['[::1%25%23]', false], 'empty host' => ['', true], + 'non idn like host #issue 5' => ['r5---sn-h0jeen7y.domain.com', true], + 'invalid host: label too long' => [implode('', array_fill(0, 64, 'a')).'.com', false], + 'invalid host: host too long' => ["$long_label.$long_label.$long_label. $long_label.$long_label", false], + 'invalid host: invalid label according to RFC3986' => ['www.fußball.com-', false], + 'invalid host: host contains space' => ['re view.com', false], ]; } }