Skip to content

Commit

Permalink
idna: split validity criteria into more specific error variants
Browse files Browse the repository at this point in the history
  • Loading branch information
djc committed Sep 14, 2020
1 parent 5428c2c commit 9331276
Showing 1 changed file with 46 additions and 24 deletions.
70 changes: 46 additions & 24 deletions idna/src/uts46.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,11 @@ fn passes_bidi(label: &str, is_bidi_domain: bool) -> bool {
/// V1 (NFC) and V8 (Bidi) are checked inside `processing()` to prevent doing duplicate work.
///
/// http://www.unicode.org/reports/tr46/#Validity_Criteria
fn is_valid(label: &str, config: Config) -> bool {
fn is_valid(label: &str, config: Config, errors: &mut Errors) {
let first_char = label.chars().next();
if first_char == None {
// Empty string, pass
return true;
return;
}

// V2: No U+002D HYPHEN-MINUS in both third and fourth positions.
Expand All @@ -294,7 +294,8 @@ fn is_valid(label: &str, config: Config) -> bool {

// V3: neither begin nor end with a U+002D HYPHEN-MINUS
if config.check_hyphens && (label.starts_with('-') || label.ends_with('-')) {
return false;
errors.check_hyphens = true;
return;
}

// V4: not contain a U+002E FULL STOP
Expand All @@ -303,7 +304,8 @@ fn is_valid(label: &str, config: Config) -> bool {

// V5: not begin with a GC=Mark
if is_combining_mark(first_char.unwrap()) {
return false;
errors.start_combining_mark = true;
return;
}

// V6: Check against Mapping Table
Expand All @@ -313,15 +315,15 @@ fn is_valid(label: &str, config: Config) -> bool {
Mapping::DisallowedStd3Valid => config.use_std3_ascii_rules,
_ => true,
}) {
return false;
errors.invalid_mapping = true;
return;
}

// V7: ContextJ rules
//
// TODO: Implement rules and add *CheckJoiners* flag.

// V8: Bidi rules are checked inside `processing()`
true
}

/// http://www.unicode.org/reports/tr46/#Processing
Expand Down Expand Up @@ -383,7 +385,7 @@ fn processing(

let mut decoder = punycode::Decoder::default();
let non_transitional = config.transitional_processing(false);
let (mut first, mut valid, mut has_bidi_labels) = (true, true, false);
let (mut first, mut has_bidi_labels) = (true, false);
for label in normalized.split('.') {
if !first {
output.push('.');
Expand All @@ -400,10 +402,12 @@ fn processing(
has_bidi_labels |= is_bidi_domain(decoded_label);
}

if valid
&& (!is_nfc(&decoded_label) || !is_valid(decoded_label, non_transitional))
{
valid = false;
if !errors.is_err() {
if !is_nfc(&decoded_label) {
errors.nfc = true;
} else {
is_valid(decoded_label, non_transitional, &mut errors);
}
}
}
Err(()) => {
Expand All @@ -417,7 +421,7 @@ fn processing(
}

// `normalized` is already `NFC` so we can skip that check
valid &= is_valid(label, config);
is_valid(label, config, &mut errors);
output.push_str(label)
}
}
Expand All @@ -427,15 +431,11 @@ fn processing(
//
// TODO: Add *CheckBidi* flag
if !passes_bidi(label, has_bidi_labels) {
valid = false;
errors.check_bidi = true;
break;
}
}

if !valid {
errors.validity_criteria = true;
}

errors
}

Expand Down Expand Up @@ -591,8 +591,11 @@ fn is_bidi_domain(s: &str) -> bool {
#[derive(Default)]
pub struct Errors {
punycode: bool,
// https://unicode.org/reports/tr46/#Validity_Criteria
validity_criteria: bool,
check_hyphens: bool,
check_bidi: bool,
start_combining_mark: bool,
invalid_mapping: bool,
nfc: bool,
disallowed_by_std3_ascii_rules: bool,
disallowed_mapped_in_std3: bool,
disallowed_character: bool,
Expand All @@ -604,15 +607,23 @@ impl Errors {
fn is_err(&self) -> bool {
let Errors {
punycode,
validity_criteria,
check_hyphens,
check_bidi,
start_combining_mark,
invalid_mapping,
nfc,
disallowed_by_std3_ascii_rules,
disallowed_mapped_in_std3,
disallowed_character,
too_long_for_dns,
too_short_for_dns,
} = *self;
punycode
|| validity_criteria
|| check_hyphens
|| check_bidi
|| start_combining_mark
|| invalid_mapping
|| nfc
|| disallowed_by_std3_ascii_rules
|| disallowed_mapped_in_std3
|| disallowed_character
Expand All @@ -625,7 +636,11 @@ impl fmt::Debug for Errors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Errors {
punycode,
validity_criteria,
check_hyphens,
check_bidi,
start_combining_mark,
invalid_mapping,
nfc,
disallowed_by_std3_ascii_rules,
disallowed_mapped_in_std3,
disallowed_character,
Expand All @@ -635,8 +650,15 @@ impl fmt::Debug for Errors {

let fields = [
("punycode", punycode),
("validity_criteria", validity_criteria),
("disallowed_by_std3_ascii_rules", disallowed_by_std3_ascii_rules),
("check_hyphens", check_hyphens),
("check_bidi", check_bidi),
("start_combining_mark", start_combining_mark),
("invalid_mapping", invalid_mapping),
("nfc", nfc),
(
"disallowed_by_std3_ascii_rules",
disallowed_by_std3_ascii_rules,
),
("disallowed_mapped_in_std3", disallowed_mapped_in_std3),
("disallowed_character", disallowed_character),
("too_long_for_dns", too_long_for_dns),
Expand Down

0 comments on commit 9331276

Please sign in to comment.