idna/
deprecated.rs
1#![allow(deprecated)]
13
14use alloc::borrow::Cow;
15use alloc::string::String;
16
17use crate::uts46::*;
18use crate::Errors;
19
20fn map_transitional(domain: &str, transitional: bool) -> Cow<'_, str> {
26 if !transitional {
27 return Cow::Borrowed(domain);
28 }
29 let mut chars = domain.chars();
30 loop {
31 let prev = chars.clone();
32 if let Some(c) = chars.next() {
33 match c {
34 'ß' | 'ẞ' | 'ς' | '\u{200C}' | '\u{200D}' => {
35 let mut s = String::with_capacity(domain.len());
36 let tail = prev.as_str();
37 let head = &domain[..domain.len() - tail.len()];
38 s.push_str(head);
39 for c in tail.chars() {
40 match c {
41 'ß' | 'ẞ' => {
42 s.push_str("ss");
43 }
44 'ς' => {
45 s.push('σ');
46 }
47 '\u{200C}' | '\u{200D}' => {}
48 _ => {
49 s.push(c);
50 }
51 }
52 }
53 return Cow::Owned(s);
54 }
55 _ => {}
56 }
57 } else {
58 break;
59 }
60 }
61 Cow::Borrowed(domain)
62}
63
64#[derive(Default)]
66#[deprecated]
67pub struct Idna {
68 config: Config,
69}
70
71impl Idna {
72 pub fn new(config: Config) -> Self {
73 Self { config }
74 }
75
76 #[allow(clippy::wrong_self_convention)] pub fn to_ascii(&mut self, domain: &str, out: &mut String) -> Result<(), Errors> {
79 let mapped = map_transitional(domain, self.config.transitional_processing);
80 match Uts46::new().process(
81 mapped.as_bytes(),
82 self.config.deny_list(),
83 self.config.hyphens(),
84 ErrorPolicy::FailFast, |_, _, _| false,
86 out,
87 None,
88 ) {
89 Ok(ProcessingSuccess::Passthrough) => {
90 if self.config.verify_dns_length && !verify_dns_length(&mapped, true) {
91 return Err(crate::Errors::default());
92 }
93 out.push_str(&mapped);
94 Ok(())
95 }
96 Ok(ProcessingSuccess::WroteToSink) => {
97 if self.config.verify_dns_length && !verify_dns_length(out, true) {
98 return Err(crate::Errors::default());
99 }
100 Ok(())
101 }
102 Err(ProcessingError::ValidityError) => Err(crate::Errors::default()),
103 Err(ProcessingError::SinkError) => unreachable!(),
104 }
105 }
106
107 #[allow(clippy::wrong_self_convention)] pub fn to_unicode(&mut self, domain: &str, out: &mut String) -> Result<(), Errors> {
110 let mapped = map_transitional(domain, self.config.transitional_processing);
111 match Uts46::new().process(
112 mapped.as_bytes(),
113 self.config.deny_list(),
114 self.config.hyphens(),
115 ErrorPolicy::MarkErrors,
116 |_, _, _| true,
117 out,
118 None,
119 ) {
120 Ok(ProcessingSuccess::Passthrough) => {
121 out.push_str(&mapped);
122 Ok(())
123 }
124 Ok(ProcessingSuccess::WroteToSink) => Ok(()),
125 Err(ProcessingError::ValidityError) => Err(crate::Errors::default()),
126 Err(ProcessingError::SinkError) => unreachable!(),
127 }
128 }
129}
130
131#[derive(Clone, Copy)]
133#[must_use]
134#[deprecated]
135pub struct Config {
136 use_std3_ascii_rules: bool,
137 transitional_processing: bool,
138 verify_dns_length: bool,
139 check_hyphens: bool,
140}
141
142impl Default for Config {
144 fn default() -> Self {
145 Config {
146 use_std3_ascii_rules: false,
147 transitional_processing: false,
148 check_hyphens: false,
149 verify_dns_length: false,
151 }
152 }
153}
154
155impl Config {
156 #[inline]
162 pub fn use_std3_ascii_rules(mut self, value: bool) -> Self {
163 self.use_std3_ascii_rules = value;
164 self
165 }
166
167 #[inline]
172 pub fn transitional_processing(mut self, value: bool) -> Self {
173 self.transitional_processing = value;
174 self
175 }
176
177 #[inline]
183 pub fn verify_dns_length(mut self, value: bool) -> Self {
184 self.verify_dns_length = value;
185 self
186 }
187
188 #[inline]
199 pub fn check_hyphens(mut self, value: bool) -> Self {
200 self.check_hyphens = value;
201 self
202 }
203
204 #[inline]
210 #[allow(unused_mut)]
211 pub fn use_idna_2008_rules(mut self, value: bool) -> Self {
212 assert!(!value, "IDNA 2008 rules are no longer supported");
213 self
214 }
215
216 fn deny_list(&self) -> AsciiDenyList {
218 if self.use_std3_ascii_rules {
219 AsciiDenyList::STD3
220 } else {
221 AsciiDenyList::EMPTY
222 }
223 }
224
225 fn hyphens(&self) -> Hyphens {
227 if self.check_hyphens {
228 Hyphens::CheckFirstLast
229 } else {
230 Hyphens::Allow
231 }
232 }
233
234 pub fn to_ascii(self, domain: &str) -> Result<String, Errors> {
236 let mut result = String::with_capacity(domain.len());
237 let mut codec = Idna::new(self);
238 codec.to_ascii(domain, &mut result).map(|()| result)
239 }
240
241 pub fn to_unicode(self, domain: &str) -> (String, Result<(), Errors>) {
243 let mut codec = Idna::new(self);
244 let mut out = String::with_capacity(domain.len());
245 let result = codec.to_unicode(domain, &mut out);
246 (out, result)
247 }
248}