1use std::{fmt, str};
6use bytes::BufMut;
7use ::bits::compose::Compose;
8use ::master::scan::{CharSource, Scan, Scanner, ScanError, Symbol};
9use super::builder::{DnameBuilder, PushError, PushNameError};
10use super::chain::{Chain, LongChainError};
11use super::dname::Dname;
12use super::relative::{DnameIter, RelativeDname};
13use super::traits::{ToDname, ToLabelIter};
14
15
16#[derive(Clone, Eq, Hash, PartialEq)]
23pub enum UncertainDname {
24 Absolute(Dname),
25 Relative(RelativeDname),
26}
27
28impl UncertainDname {
29 pub fn absolute(name: Dname) -> Self {
31 UncertainDname::Absolute(name)
32 }
33
34 pub fn relative(name: RelativeDname) -> Self {
36 UncertainDname::Relative(name)
37 }
38
39 pub fn root() -> Self {
41 UncertainDname::Absolute(Dname::root())
42 }
43
44 pub fn empty() -> Self {
46 UncertainDname::Relative(RelativeDname::empty())
47 }
48
49 pub fn from_chars<C>(chars: C) -> Result<Self, FromStrError>
64 where C: IntoIterator<Item=char> {
65 Self::_from_chars(chars.into_iter(), DnameBuilder::new())
66 }
67
68 fn _from_chars<C>(mut chars: C, mut target: DnameBuilder)
70 -> Result<Self, FromStrError>
71 where C: Iterator<Item=char> {
72 while let Some(ch) = chars.next() {
73 match ch {
74 '.' => {
75 if !target.in_label() {
76 return Err(FromStrError::EmptyLabel)
77 }
78 target.end_label();
79 }
80 '\\' => {
81 let in_label = target.in_label();
82 target.push(parse_escape(&mut chars, in_label)?)?;
83 }
84 ' ' ... '-' | '/' ... '[' | ']' ... '~' => {
85 target.push(ch as u8)?
86 }
87 _ => return Err(FromStrError::IllegalCharacter(ch))
88 }
89 }
90 if target.in_label() || target.is_empty() {
91 Ok(target.finish().into())
92 }
93 else {
94 target.into_dname().map(Into::into)
95 .map_err(|_| FromStrError::LongName)
96 }
97 }
98
99 pub fn is_absolute(&self) -> bool {
101 match *self {
102 UncertainDname::Absolute(_) => true,
103 UncertainDname::Relative(_) => false,
104 }
105 }
106
107 pub fn is_relative(&self) -> bool {
109 !self.is_absolute()
110 }
111
112 pub fn as_absolute(&self) -> Option<&Dname> {
114 match *self {
115 UncertainDname::Absolute(ref name) => Some(name),
116 _ => None
117 }
118 }
119
120 pub fn as_relative(&self) -> Option<&RelativeDname> {
122 match *self {
123 UncertainDname::Relative(ref name) => Some(name),
124 _ => None,
125 }
126 }
127
128 pub fn try_into_absolute(self) -> Result<Dname, Self> {
132 if let UncertainDname::Absolute(name) = self {
133 Ok(name)
134 }
135 else {
136 Err(self)
137 }
138 }
139
140 pub fn try_into_relative(self) -> Result<RelativeDname, Self> {
144 if let UncertainDname::Relative(name) = self {
145 Ok(name)
146 }
147 else {
148 Err(self)
149 }
150 }
151
152 pub fn into_absolute(self) -> Dname {
160 match self {
161 UncertainDname::Absolute(name) => name,
162 UncertainDname::Relative(name) => name.into_absolute()
163 }
164 }
165
166 pub fn chain<S: ToDname>(self, suffix: S)
173 -> Result<Chain<Self, S>, LongChainError> {
174 Chain::new_uncertain(self, suffix)
175 }
176
177 pub fn as_slice(&self) -> &[u8] {
179 match *self {
180 UncertainDname::Absolute(ref name) => name.as_slice(),
181 UncertainDname::Relative(ref name) => name.as_slice(),
182 }
183 }
184}
185
186
187impl Compose for UncertainDname {
190 fn compose_len(&self) -> usize {
191 match *self {
192 UncertainDname::Absolute(ref name) => name.compose_len(),
193 UncertainDname::Relative(ref name) => name.compose_len(),
194 }
195 }
196
197 fn compose<B: BufMut>(&self, buf: &mut B) {
198 match *self {
199 UncertainDname::Absolute(ref name) => name.compose(buf),
200 UncertainDname::Relative(ref name) => name.compose(buf),
201 }
202 }
203}
204
205
206impl From<Dname> for UncertainDname {
209 fn from(name: Dname) -> Self {
210 Self::absolute(name)
211 }
212}
213
214impl From<RelativeDname> for UncertainDname {
215 fn from(name: RelativeDname) -> Self {
216 Self::relative(name)
217 }
218}
219
220
221impl str::FromStr for UncertainDname {
224 type Err = FromStrError;
225
226 fn from_str(s: &str) -> Result<Self, Self::Err> {
227 Self::_from_chars(s.chars(), DnameBuilder::with_capacity(s.len()))
228 }
229}
230
231
232impl Scan for UncertainDname {
235 fn scan<C: CharSource>(scanner: &mut Scanner<C>)
236 -> Result<Self, ScanError> {
237 if let Ok(()) = scanner.skip_literal(".") {
238 return Ok(UncertainDname::root())
239 }
240 scanner.scan_word(
241 DnameBuilder::new(),
242 |name, symbol| {
243 match symbol {
244 Symbol::Char('.') => {
245 if name.in_label() {
246 name.end_label();
247 }
248 else {
249 return Err(FromStrError::EmptyLabel.into())
250 }
251 }
252 Symbol::Char(ch) | Symbol::SimpleEscape(ch) => {
253 if ch.is_ascii() {
254 if let Err(err) = name.push(ch as u8) {
255 return Err(FromStrError::from(err).into())
256 }
257 }
258 else {
259 return Err(FromStrError::IllegalCharacter(ch)
260 .into())
261 }
262 }
263 Symbol::DecimalEscape(ch) => {
264 if let Err(err) = name.push(ch) {
265 return Err(FromStrError::from(err).into())
266 }
267 }
268 }
269 Ok(())
270 },
271 |name| {
272 if name.in_label() || name.is_empty() {
273 Ok(name.finish().into())
274 }
275 else {
276 name.into_dname()
277 .map(Into::into)
278 .map_err(|err| FromStrError::from(err).into())
279 }
280 }
281 )
282 }
283}
284
285
286impl<'a> ToLabelIter<'a> for UncertainDname {
289 type LabelIter = DnameIter<'a>;
290
291 fn iter_labels(&'a self) -> Self::LabelIter {
292 match *self {
293 UncertainDname::Absolute(ref name) => name.iter_labels(),
294 UncertainDname::Relative(ref name) => name.iter_labels(),
295 }
296 }
297}
298
299
300impl fmt::Display for UncertainDname {
303 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304 match *self {
305 UncertainDname::Absolute(ref name) => name.fmt(f),
306 UncertainDname::Relative(ref name) => name.fmt(f),
307 }
308 }
309}
310
311impl fmt::Debug for UncertainDname {
312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313 match *self {
314 UncertainDname::Absolute(ref name) => {
315 write!(f, "UncertainDname::Absolute({})", name)
316 }
317 UncertainDname::Relative(ref name) => {
318 write!(f, "UncertainDname::Relative({})", name)
319 }
320 }
321 }
322}
323
324
325fn parse_escape<C>(chars: &mut C, in_label: bool) -> Result<u8, FromStrError>
331 where C: Iterator<Item=char> {
332 let ch = try!(chars.next().ok_or(FromStrError::UnexpectedEnd));
333 if ch >= '0' && ch <= '9' {
334 let v = ch.to_digit(10).unwrap() * 100
335 + try!(chars.next().ok_or(FromStrError::UnexpectedEnd)
336 .and_then(|c| c.to_digit(10)
337 .ok_or(FromStrError::IllegalEscape)))
338 * 10
339 + try!(chars.next().ok_or(FromStrError::UnexpectedEnd)
340 .and_then(|c| c.to_digit(10)
341 .ok_or(FromStrError::IllegalEscape)));
342 if v > 255 {
343 return Err(FromStrError::IllegalEscape)
344 }
345 Ok(v as u8)
346 }
347 else if ch == '[' {
348 if in_label {
351 Ok(b'[')
352 }
353 else {
354 Err(FromStrError::BinaryLabel)
355 }
356 }
357 else { Ok(ch as u8) }
358}
359
360
361#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
364pub enum FromStrError {
365 #[fail(display="unexpected end of input")]
369 UnexpectedEnd,
370
371 #[fail(display="an empty label was encountered")]
373 EmptyLabel,
374
375 #[fail(display="a binary label was encountered")]
377 BinaryLabel,
378
379 #[fail(display="label length limit exceeded")]
381 LongLabel,
382
383 #[fail(display="illegal escape sequence")]
389 IllegalEscape,
390
391 #[fail(display="illegal character '{}'", _0)]
395 IllegalCharacter(char),
396
397 #[fail(display="long domain name")]
399 LongName,
400}
401
402impl From<PushError> for FromStrError {
403 fn from(err: PushError) -> FromStrError {
404 match err {
405 PushError::LongLabel => FromStrError::LongLabel,
406 PushError::LongName => FromStrError::LongName,
407 }
408 }
409}
410
411impl From<PushNameError> for FromStrError {
412 fn from(_: PushNameError) -> FromStrError {
413 FromStrError::LongName
414 }
415}
416
417
418#[cfg(test)]
421mod test {
422 use super::*;
423
424 #[test]
425 fn from_str() {
426 use std::str::FromStr;
427
428 fn name(s: &str) -> UncertainDname {
429 UncertainDname::from_str(s).unwrap()
430 }
431
432 assert_eq!(name("www.example.com").as_relative().unwrap().as_slice(),
433 b"\x03www\x07example\x03com");
434 assert_eq!(name("www.example.com.").as_absolute().unwrap().as_slice(),
435 b"\x03www\x07example\x03com\0");
436
437 assert_eq!(name(r"www\.example.com").as_slice(),
438 b"\x0bwww.example\x03com");
439 assert_eq!(name(r"w\119w.example.com").as_slice(),
440 b"\x03www\x07example\x03com");
441 assert_eq!(name(r"w\000w.example.com").as_slice(),
442 b"\x03w\0w\x07example\x03com");
443
444 assert_eq!(UncertainDname::from_str(r"w\01"),
445 Err(FromStrError::UnexpectedEnd));
446 assert_eq!(UncertainDname::from_str(r"w\"),
447 Err(FromStrError::UnexpectedEnd));
448 assert_eq!(UncertainDname::from_str(r"www..example.com"),
449 Err(FromStrError::EmptyLabel));
450 assert_eq!(UncertainDname::from_str(r"www.example.com.."),
451 Err(FromStrError::EmptyLabel));
452 assert_eq!(UncertainDname::from_str(r".www.example.com"),
453 Err(FromStrError::EmptyLabel));
454 assert_eq!(UncertainDname::from_str(r"www.\[322].example.com"),
455 Err(FromStrError::BinaryLabel));
456 assert_eq!(UncertainDname::from_str(r"www.\2example.com"),
457 Err(FromStrError::IllegalEscape));
458 assert_eq!(UncertainDname::from_str(r"www.\29example.com"),
459 Err(FromStrError::IllegalEscape));
460 assert_eq!(UncertainDname::from_str(r"www.\299example.com"),
461 Err(FromStrError::IllegalEscape));
462 assert_eq!(UncertainDname::from_str(r"www.\892example.com"),
463 Err(FromStrError::IllegalEscape));
464 assert_eq!(UncertainDname::from_str("www.e\0ample.com"),
465 Err(FromStrError::IllegalCharacter('\0')));
466 assert_eq!(UncertainDname::from_str("www.eüample.com"),
467 Err(FromStrError::IllegalCharacter('ü')));
468
469 let mut s = String::from("www.");
471 for _ in 0..63 {
472 s.push('x');
473 }
474 s.push_str(".com");
475 assert!(UncertainDname::from_str(&s).is_ok());
476 let mut s = String::from("www.");
477 for _ in 0..64 {
478 s.push('x');
479 }
480 s.push_str(".com");
481 assert_eq!(UncertainDname::from_str(&s),
482 Err(FromStrError::LongLabel));
483
484 let mut s = String::new();
486 for _ in 0..50 {
487 s.push_str("four.");
488 }
489 let mut s1 = s.clone();
490 s1.push_str("com.");
491 assert_eq!(name(&s1).as_slice().len(), 255);
492 let mut s1 = s.clone();
493 s1.push_str("com");
494 assert_eq!(name(&s1).as_slice().len(), 254);
495 let mut s1 = s.clone();
496 s1.push_str("coma.");
497 assert_eq!(UncertainDname::from_str(&s1), Err(FromStrError::LongName));
498 let mut s1 = s.clone();
499 s1.push_str("coma");
500 assert_eq!(UncertainDname::from_str(&s1), Err(FromStrError::LongName));
501 }
502}