11
11
12
12
use self :: Mapping :: * ;
13
13
use crate :: punycode;
14
- use std:: cmp:: Ordering :: { Equal , Greater , Less } ;
15
14
use std:: { error:: Error as StdError , fmt} ;
16
15
use unicode_bidi:: { bidi_class, BidiClass } ;
17
16
use unicode_normalization:: char:: is_combining_mark;
@@ -48,38 +47,26 @@ enum Mapping {
48
47
Disallowed ,
49
48
DisallowedStd3Valid ,
50
49
DisallowedStd3Mapped ( StringTableSlice ) ,
51
- }
52
-
53
- struct Range {
54
- from : char ,
55
- to : char ,
50
+ DisallowedIdna2008 ,
56
51
}
57
52
58
53
fn find_char ( codepoint : char ) -> & ' static Mapping {
59
- let r = TABLE . binary_search_by ( |ref range| {
60
- if codepoint > range. to {
61
- Less
62
- } else if codepoint < range. from {
63
- Greater
64
- } else {
65
- Equal
66
- }
67
- } ) ;
68
- r. ok ( )
69
- . map ( |i| {
70
- const SINGLE_MARKER : u16 = 1 << 15 ;
54
+ let idx = match TABLE . binary_search_by_key ( & codepoint, |& val| val. 0 ) {
55
+ Ok ( idx) => idx,
56
+ Err ( idx) => idx - 1 ,
57
+ } ;
71
58
72
- let x = INDEX_TABLE [ i] ;
73
- let single = ( x & SINGLE_MARKER ) != 0 ;
74
- let offset = !SINGLE_MARKER & x;
59
+ const SINGLE_MARKER : u16 = 1 << 15 ;
75
60
76
- if single {
77
- & MAPPING_TABLE [ offset as usize ]
78
- } else {
79
- & MAPPING_TABLE [ ( offset + ( codepoint as u16 - TABLE [ i] . from as u16 ) ) as usize ]
80
- }
81
- } )
82
- . unwrap ( )
61
+ let ( base, x) = TABLE [ idx] ;
62
+ let single = ( x & SINGLE_MARKER ) != 0 ;
63
+ let offset = !SINGLE_MARKER & x;
64
+
65
+ if single {
66
+ & MAPPING_TABLE [ offset as usize ]
67
+ } else {
68
+ & MAPPING_TABLE [ ( offset + ( codepoint as u16 - base as u16 ) ) as usize ]
69
+ }
83
70
}
84
71
85
72
struct Mapper < ' a > {
@@ -140,6 +127,12 @@ impl<'a> Iterator for Mapper<'a> {
140
127
self . slice = Some ( decode_slice ( slice) . chars ( ) ) ;
141
128
continue ;
142
129
}
130
+ Mapping :: DisallowedIdna2008 => {
131
+ if self . config . use_idna_2008_rules {
132
+ self . errors . disallowed_in_idna_2008 = true ;
133
+ }
134
+ codepoint
135
+ }
143
136
} ) ;
144
137
}
145
138
}
@@ -310,7 +303,7 @@ fn check_validity(label: &str, config: Config, errors: &mut Errors) {
310
303
311
304
// V6: Check against Mapping Table
312
305
if label. chars ( ) . any ( |c| match * find_char ( c) {
313
- Mapping :: Valid => false ,
306
+ Mapping :: Valid | Mapping :: DisallowedIdna2008 => false ,
314
307
Mapping :: Deviation ( _) => config. transitional_processing ,
315
308
Mapping :: DisallowedStd3Valid => config. use_std3_ascii_rules ,
316
309
_ => true ,
@@ -510,6 +503,7 @@ pub struct Config {
510
503
transitional_processing : bool ,
511
504
verify_dns_length : bool ,
512
505
check_hyphens : bool ,
506
+ use_idna_2008_rules : bool ,
513
507
}
514
508
515
509
/// The defaults are that of https://url.spec.whatwg.org/#idna
@@ -524,6 +518,7 @@ impl Default for Config {
524
518
525
519
// Only use for to_ascii, not to_unicode
526
520
verify_dns_length : false ,
521
+ use_idna_2008_rules : false ,
527
522
}
528
523
}
529
524
}
@@ -553,6 +548,12 @@ impl Config {
553
548
self
554
549
}
555
550
551
+ #[ inline]
552
+ pub fn use_idna_2008_rules ( mut self , value : bool ) -> Self {
553
+ self . use_idna_2008_rules = value;
554
+ self
555
+ }
556
+
556
557
/// http://www.unicode.org/reports/tr46/#ToASCII
557
558
pub fn to_ascii ( self , domain : & str ) -> Result < String , Errors > {
558
559
let mut result = String :: new ( ) ;
@@ -599,6 +600,7 @@ pub struct Errors {
599
600
disallowed_character : bool ,
600
601
too_long_for_dns : bool ,
601
602
too_short_for_dns : bool ,
603
+ disallowed_in_idna_2008 : bool ,
602
604
}
603
605
604
606
impl Errors {
@@ -615,6 +617,7 @@ impl Errors {
615
617
disallowed_character,
616
618
too_long_for_dns,
617
619
too_short_for_dns,
620
+ disallowed_in_idna_2008,
618
621
} = * self ;
619
622
punycode
620
623
|| check_hyphens
@@ -627,6 +630,7 @@ impl Errors {
627
630
|| disallowed_character
628
631
|| too_long_for_dns
629
632
|| too_short_for_dns
633
+ || disallowed_in_idna_2008
630
634
}
631
635
}
632
636
@@ -644,6 +648,7 @@ impl fmt::Debug for Errors {
644
648
disallowed_character,
645
649
too_long_for_dns,
646
650
too_short_for_dns,
651
+ disallowed_in_idna_2008,
647
652
} = * self ;
648
653
649
654
let fields = [
@@ -661,6 +666,7 @@ impl fmt::Debug for Errors {
661
666
( "disallowed_character" , disallowed_character) ,
662
667
( "too_long_for_dns" , too_long_for_dns) ,
663
668
( "too_short_for_dns" , too_short_for_dns) ,
669
+ ( "disallowed_in_idna_2008" , disallowed_in_idna_2008) ,
664
670
] ;
665
671
666
672
let mut empty = true ;
0 commit comments