2
2
//!
3
3
//! https://url.spec.whatwg.org/#idna
4
4
5
- use idna_mapping :: TABLE ;
5
+ use self :: Mapping :: * ;
6
6
use punycode;
7
7
use std:: ascii:: AsciiExt ;
8
8
use unicode_normalization:: UnicodeNormalization ;
9
9
use unicode_normalization:: char:: is_combining_mark;
10
10
use unicode_bidi:: { BidiClass , bidi_class} ;
11
11
12
+ include ! ( "idna_mapping.rs" ) ;
13
+
12
14
#[ derive( Debug ) ]
13
- pub enum Mapping {
15
+ enum Mapping {
14
16
Valid ,
15
17
Ignored ,
16
18
Mapped ( & ' static str ) ,
@@ -20,7 +22,7 @@ pub enum Mapping {
20
22
DisallowedStd3Mapped ( & ' static str ) ,
21
23
}
22
24
23
- pub struct Range {
25
+ struct Range {
24
26
pub from : char ,
25
27
pub to : char ,
26
28
pub mapping : Mapping ,
@@ -43,7 +45,7 @@ fn find_char(codepoint: char) -> &'static Mapping {
43
45
& TABLE [ min] . mapping
44
46
}
45
47
46
- fn map_char ( codepoint : char , flags : Uts46Flags , output : & mut String ) -> Result < ( ) , Error > {
48
+ fn map_char ( codepoint : char , flags : Uts46Flags , output : & mut String , errors : & mut Vec < Error > ) {
47
49
match * find_char ( codepoint) {
48
50
Mapping :: Valid => output. push ( codepoint) ,
49
51
Mapping :: Ignored => { } ,
@@ -55,23 +57,23 @@ fn map_char(codepoint: char, flags: Uts46Flags, output: &mut String) -> Result<(
55
57
output. push ( codepoint)
56
58
}
57
59
}
58
- Mapping :: Disallowed => return Err ( Error :: DissallowedCharacter ) ,
60
+ Mapping :: Disallowed => {
61
+ errors. push ( Error :: DissallowedCharacter ) ;
62
+ output. push ( codepoint) ;
63
+ }
59
64
Mapping :: DisallowedStd3Valid => {
60
65
if flags. use_std3_ascii_rules {
61
- return Err ( Error :: DissallowedByStd3AsciiRules ) ;
62
- } else {
63
- output. push ( codepoint)
66
+ errors. push ( Error :: DissallowedByStd3AsciiRules ) ;
64
67
}
68
+ output. push ( codepoint)
65
69
}
66
70
Mapping :: DisallowedStd3Mapped ( mapping) => {
67
71
if flags. use_std3_ascii_rules {
68
- return Err ( Error :: DissallowedMappedInStd3 ) ;
69
- } else {
70
- output. push_str ( mapping)
72
+ errors. push ( Error :: DissallowedMappedInStd3 ) ;
71
73
}
74
+ output. push_str ( mapping)
72
75
}
73
76
}
74
- Ok ( ( ) )
75
77
}
76
78
77
79
// http://tools.ietf.org/html/rfc5893#section-2
@@ -183,9 +185,9 @@ fn passes_bidi(label: &str, transitional_processing: bool) -> bool {
183
185
}
184
186
185
187
/// http://www.unicode.org/reports/tr46/#Validity_Criteria
186
- fn validate ( label : & str , flags : Uts46Flags ) -> Result < ( ) , Error > {
188
+ fn validate ( label : & str , flags : Uts46Flags , errors : & mut Vec < Error > ) {
187
189
if label. nfc ( ) . ne ( label. chars ( ) ) {
188
- return Err ( Error :: ValidityCriteria ) ;
190
+ errors . push ( Error :: ValidityCriteria ) ;
189
191
}
190
192
191
193
// Can not contain '.' since the input is from .split('.')
@@ -205,17 +207,15 @@ fn validate(label: &str, flags: Uts46Flags) -> Result<(), Error> {
205
207
} )
206
208
|| !passes_bidi ( label, flags. transitional_processing )
207
209
{
208
- Err ( Error :: ValidityCriteria )
209
- } else {
210
- Ok ( ( ) )
210
+ errors. push ( Error :: ValidityCriteria )
211
211
}
212
212
}
213
213
214
214
/// http://www.unicode.org/reports/tr46/#Processing
215
- fn uts46_processing ( domain : & str , flags : Uts46Flags ) -> Result < String , Error > {
215
+ fn uts46_processing ( domain : & str , flags : Uts46Flags , errors : & mut Vec < Error > ) -> String {
216
216
let mut mapped = String :: new ( ) ;
217
217
for c in domain. chars ( ) {
218
- try! ( map_char ( c, flags, & mut mapped) )
218
+ map_char ( c, flags, & mut mapped, errors )
219
219
}
220
220
let normalized: String = mapped. nfc ( ) . collect ( ) ;
221
221
let mut validated = String :: new ( ) ;
@@ -225,21 +225,19 @@ fn uts46_processing(domain: &str, flags: Uts46Flags) -> Result<String, Error> {
225
225
}
226
226
if label. starts_with ( "xn--" ) {
227
227
match punycode:: decode_to_string ( & label[ "xn--" . len ( ) ..] ) {
228
- Some ( label) => {
229
- try!( validate ( & label, Uts46Flags {
230
- transitional_processing : false ,
231
- ..flags
232
- } ) ) ;
233
- validated. push_str ( & label)
228
+ Some ( decoded_label) => {
229
+ let flags = Uts46Flags { transitional_processing : false , ..flags } ;
230
+ validate ( & decoded_label, flags, errors) ;
231
+ validated. push_str ( & decoded_label)
234
232
}
235
- None => return Err ( Error :: PunycodeError ) ,
233
+ None => errors . push ( Error :: PunycodeError )
236
234
}
237
235
} else {
238
- try! ( validate ( label, flags) ) ;
236
+ validate ( label, flags, errors ) ;
239
237
validated. push_str ( label)
240
238
}
241
239
}
242
- Ok ( validated)
240
+ validated
243
241
}
244
242
245
243
#[ derive( Copy , Clone ) ]
@@ -260,9 +258,10 @@ pub enum Error {
260
258
}
261
259
262
260
/// http://www.unicode.org/reports/tr46/#ToASCII
263
- pub fn uts46_to_ascii ( domain : & str , flags : Uts46Flags ) -> Result < String , Error > {
261
+ pub fn uts46_to_ascii ( domain : & str , flags : Uts46Flags ) -> Result < String , Vec < Error > > {
262
+ let mut errors = Vec :: new ( ) ;
264
263
let mut result = String :: new ( ) ;
265
- for label in try! ( uts46_processing ( domain, flags) ) . split ( '.' ) {
264
+ for label in uts46_processing ( domain, flags, & mut errors ) . split ( '.' ) {
266
265
if result. len ( ) > 0 {
267
266
result. push ( '.' ) ;
268
267
}
@@ -274,7 +273,7 @@ pub fn uts46_to_ascii(domain: &str, flags: Uts46Flags) -> Result<String, Error>
274
273
result. push_str ( "xn--" ) ;
275
274
result. push_str ( & x) ;
276
275
} ,
277
- None => return Err ( Error :: PunycodeError )
276
+ None => errors . push ( Error :: PunycodeError )
278
277
}
279
278
}
280
279
}
@@ -283,17 +282,42 @@ pub fn uts46_to_ascii(domain: &str, flags: Uts46Flags) -> Result<String, Error>
283
282
let domain = if result. ends_with ( "." ) { & result[ ..result. len ( ) -1 ] } else { & * result } ;
284
283
if domain. len ( ) < 1 || domain. len ( ) > 253 ||
285
284
domain. split ( '.' ) . any ( |label| label. len ( ) < 1 || label. len ( ) > 63 ) {
286
- return Err ( Error :: TooLongForDns )
285
+ errors . push ( Error :: TooLongForDns )
287
286
}
288
287
}
289
- Ok ( result)
288
+ if errors. is_empty ( ) {
289
+ Ok ( result)
290
+ } else {
291
+ Err ( errors)
292
+ }
290
293
}
291
294
292
295
/// https://url.spec.whatwg.org/#concept-domain-to-ascii
293
- pub fn domain_to_ascii ( domain : & str ) -> Result < String , Error > {
296
+ pub fn domain_to_ascii ( domain : & str ) -> Result < String , Vec < Error > > {
294
297
uts46_to_ascii ( domain, Uts46Flags {
295
298
use_std3_ascii_rules : false ,
296
299
transitional_processing : true , // XXX: switch when Firefox does
297
300
verify_dns_length : false ,
298
301
} )
299
302
}
303
+
304
+ /// http://www.unicode.org/reports/tr46/#ToUnicode
305
+ ///
306
+ /// Only `use_std3_ascii_rules` is used in `flags`.
307
+ pub fn uts46_to_unicode ( domain : & str , mut flags : Uts46Flags ) -> ( String , Vec < Error > ) {
308
+ flags. transitional_processing = false ;
309
+ let mut errors = Vec :: new ( ) ;
310
+ let domain = uts46_processing ( domain, flags, & mut errors) ;
311
+ ( domain, errors)
312
+ }
313
+
314
+ /// https://url.spec.whatwg.org/#concept-domain-to-unicode
315
+ pub fn domain_to_unicode ( domain : & str ) -> ( String , Vec < Error > ) {
316
+ uts46_to_unicode ( domain, Uts46Flags {
317
+ use_std3_ascii_rules : false ,
318
+
319
+ // Unused:
320
+ transitional_processing : true ,
321
+ verify_dns_length : false ,
322
+ } )
323
+ }
0 commit comments