1use crate::{
2 Error, Result,
3 bytes::{Cursor, Reader},
4 constants::DOMAIN_NAME_MAX_LENGTH,
5 names::InlineName,
6};
7use std::{
8 cmp::Ordering,
9 fmt::{self, Display, Formatter},
10 hash::{Hash, Hasher},
11 str::FromStr,
12};
13
14#[derive(Debug, Default, Clone)]
48pub struct Name {
49 name: String,
50}
51
52impl Name {
53 #[inline(always)]
65 pub fn new() -> Self {
66 Self {
67 name: Default::default(),
68 }
69 }
70
71 pub fn root() -> Self {
83 Self {
84 name: String::from("."),
85 }
86 }
87
88 fn from(s: &str) -> Result<Self> {
89 super::check_name(s)?;
90
91 let mut dn = Self {
92 name: String::from(s),
95 };
96
97 let bytes = s.as_bytes();
98
99 let last_byte = unsafe { *bytes.get_unchecked(bytes.len() - 1) };
101
102 if last_byte != b'.' {
103 dn.name.push('.');
107 }
108
109 Ok(dn)
110 }
111
112 #[inline(always)]
136 pub fn as_str(&self) -> &str {
137 &self.name
138 }
139
140 #[inline(always)]
164 pub fn len(&self) -> usize {
165 self.name.len()
166 }
167
168 #[inline(always)]
191 pub fn is_empty(&self) -> bool {
192 self.name.is_empty()
193 }
194
195 #[inline(always)]
220 pub fn clear(&mut self) {
221 self.name.clear();
222 }
223
224 pub(crate) fn append_label_bytes(&mut self, label: &[u8]) -> Result<()> {
225 super::check_label_bytes(label)?;
226
227 let label_as_str = unsafe { std::str::from_utf8_unchecked(label) };
230
231 let new_len = self.name.len() + label_as_str.len() + 1;
232 if new_len > DOMAIN_NAME_MAX_LENGTH {
233 return Err(Error::DomainNameTooLong(new_len));
234 }
235
236 self.name.push_str(label_as_str);
237 self.name.push('.');
238
239 Ok(())
240 }
241
242 pub(crate) fn append_label(&mut self, label: &str) -> Result<()> {
243 super::check_label(label)?;
244
245 let new_len = self.name.len() + label.len() + 1;
246 if new_len > DOMAIN_NAME_MAX_LENGTH {
247 return Err(Error::DomainNameTooLong(new_len));
248 }
249
250 self.name.push_str(label);
251 self.name.push('.');
252
253 Ok(())
254 }
255
256 pub fn set_root(&mut self) {
283 self.name.clear();
284 self.name.push('.');
285 }
286}
287
288impl TryFrom<&str> for Name {
289 type Error = Error;
290
291 fn try_from(value: &str) -> Result<Self> {
292 Self::from(value)
293 }
294}
295
296impl FromStr for Name {
297 type Err = Error;
298
299 fn from_str(s: &str) -> Result<Self> {
300 Self::from(s)
301 }
302}
303
304impl AsRef<str> for Name {
305 fn as_ref(&self) -> &str {
306 &self.name
307 }
308}
309
310impl PartialEq for Name {
311 fn eq(&self, other: &Self) -> bool {
312 self.name
313 .as_bytes()
314 .eq_ignore_ascii_case(other.name.as_bytes())
315 }
316}
317
318impl PartialOrd for Name {
319 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
320 Some(self.cmp(other))
321 }
322}
323
324impl Ord for Name {
325 fn cmp(&self, other: &Self) -> Ordering {
326 for i in 0..self.len().min(other.len()) {
327 let left = unsafe { self.name.as_bytes().get_unchecked(i) };
328 let right = unsafe { other.name.as_bytes().get_unchecked(i) };
329 let ord = left.to_ascii_lowercase().cmp(&right.to_ascii_lowercase());
330 if Ordering::Equal != ord {
331 return ord;
332 }
333 }
334 self.len().cmp(&other.len())
335 }
336}
337
338impl PartialEq<&str> for Name {
339 fn eq(&self, other: &&str) -> bool {
340 let l_is_root = self.name.as_bytes() == b".";
341 let r_is_root = *other == ".";
342
343 match (l_is_root, r_is_root) {
344 (true, true) => return true,
345 (false, false) => {}
346 _ => return false,
347 }
348
349 let mut bytes = self.name.as_bytes();
350 if !bytes.is_empty() && !other.ends_with('.') {
351 bytes = &bytes[..bytes.len() - 1];
352 }
353
354 bytes.eq_ignore_ascii_case(other.as_bytes())
355 }
356}
357
358impl Eq for Name {}
359
360impl Hash for Name {
361 fn hash<H: Hasher>(&self, state: &mut H) {
362 for b in self.name.as_bytes() {
363 state.write_u8(b.to_ascii_lowercase());
364 }
365 }
366}
367
368impl Display for Name {
369 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
370 f.pad(self.as_str())
371 }
372}
373
374impl From<Name> for String {
375 fn from(name: Name) -> Self {
376 name.name
377 }
378}
379
380impl From<InlineName> for Name {
381 fn from(name: InlineName) -> Self {
382 Self {
383 name: name.as_str().to_string(),
384 }
385 }
386}
387
388impl From<&InlineName> for Name {
389 fn from(name: &InlineName) -> Self {
390 Self {
391 name: name.as_str().to_string(),
392 }
393 }
394}
395
396impl super::private::DNameBase for Name {
397 #[inline(always)]
398 fn as_str(&self) -> &str {
399 self.as_str()
400 }
401
402 #[inline(always)]
403 fn len(&self) -> usize {
404 self.len()
405 }
406
407 #[inline(always)]
408 fn is_empty(&self) -> bool {
409 self.is_empty()
410 }
411
412 #[inline(always)]
413 fn clear(&mut self) {
414 self.clear()
415 }
416
417 #[inline(always)]
418 fn append_label_bytes(&mut self, label: &[u8]) -> Result<()> {
419 self.append_label_bytes(label)
420 }
421
422 #[inline(always)]
423 fn append_label(&mut self, label: &str) -> Result<()> {
424 self.append_label(label)
425 }
426
427 #[inline(always)]
428 fn set_root(&mut self) {
429 self.set_root()
430 }
431
432 #[inline(always)]
433 fn from_cursor(c: &mut Cursor<'_>) -> Result<Self> {
434 c.read()
435 }
436}
437
438impl super::DName for Name {}
439
440#[cfg(test)]
441mod tests {
442 use super::*;
443 use std::collections::HashSet;
444
445 #[test]
446 fn test_new() {
447 let dn = Name::new();
448
449 assert!(dn.is_empty());
450 assert_eq!(dn.len(), 0);
451 }
452
453 #[test]
454 fn test_default() {
455 let dn: Name = Default::default();
456
457 assert!(dn.is_empty());
458 assert_eq!(dn.len(), 0);
459 }
460
461 #[test]
462 fn test_from() {
463 let label_63 = "a".repeat(63);
464 let label_61 = "b".repeat(60);
465
466 let dn_253 = [
467 label_63.as_str(),
468 label_63.as_str(),
469 label_63.as_str(),
470 label_61.as_str(),
471 ]
472 .join(".");
473
474 let dn_254 = dn_253.clone() + ".";
475
476 let dn_255 = [
477 label_63.as_str(),
478 label_63.as_str(),
479 label_63.as_str(),
480 label_63.as_str(),
481 ]
482 .join(".");
483
484 let success_cases = &[
485 "3om",
486 "com",
487 "example.com",
488 "sub.example.com",
489 "3ub.example.com",
490 ".",
491 "example.com.",
492 "3xample.com.",
493 "EXAMPLE.com",
494 "EXAMPLE.COM",
495 "EXAMPLE.COM.",
496 dn_253.as_str(),
497 dn_254.as_str(),
498 ];
499
500 for sc in success_cases {
501 let dn = Name::from(sc).unwrap();
502 let expected = if sc.ends_with('.') {
503 sc.to_string()
504 } else {
505 format!("{sc}.")
506 };
507 assert_eq!(dn.as_str(), &expected);
508 assert_eq!(dn.len(), expected.len());
509 }
510
511 let failure_cases = &[
512 "",
513 "..",
514 "3c-",
515 "co-",
516 "example..com",
517 "sub..example.com",
518 "example-.com",
519 "-xample.com",
520 "examp|e.com",
521 "exa\u{203C}ple.com",
522 dn_255.as_str(),
523 ];
524
525 for fc in failure_cases {
526 assert!(Name::from(fc).is_err())
527 }
528 }
529
530 #[test]
531 fn test_len() {
532 let mut dn = Name::new();
533 assert_eq!(dn.len(), 0);
534
535 dn.append_label("example").unwrap();
536 assert_eq!(dn.len(), 8);
537
538 dn.append_label("com").unwrap();
539 assert_eq!(dn.len(), 12);
540 }
541
542 #[test]
543 fn test_append_label_too_long() {
544 let l_63 = "a".repeat(63);
545 let l_62 = "b".repeat(62);
546
547 let mut dn = Name::new();
548
549 dn.append_label(&l_63).unwrap();
550 assert_eq!(dn.len(), 64);
551
552 dn.append_label(&l_63).unwrap();
553 assert_eq!(dn.len(), 128);
554
555 dn.append_label(&l_63).unwrap();
556 assert_eq!(dn.len(), 192);
557
558 {
560 let mut dn = dn.clone();
561 dn.append_label("small").unwrap();
562
563 let res = dn.append_label(&l_63);
564 assert!(
565 matches!(res, Err(Error::DomainNameTooLong(s)) if s == dn.len() + l_63.len() + 1)
566 );
567 }
568
569 let res = dn.clone().append_label(&l_63);
571 assert!(matches!(res, Err(Error::DomainNameTooLong(s)) if s == dn.len() + l_63.len() + 1));
572
573 dn.append_label(&l_62).unwrap();
574 assert_eq!(dn.len(), 255);
575 }
576
577 #[test]
578 fn test_eq() {
579 let dn1 = Name::from("example.com").unwrap();
580 let dn2 = Name::from("EXAMPLE.COM").unwrap();
581 let dn3 = Name::from("eXaMpLe.cOm").unwrap();
582
583 assert_eq!(dn1, dn2);
584 assert_eq!(dn1, dn3);
585 assert_eq!(dn2, dn3);
586 }
587
588 #[test]
589 fn test_neq() {
590 let dn1 = Name::from("example.com").unwrap();
591 let dn2 = Name::from("sub.example.com").unwrap();
592 let dn3 = Name::from("Sub.examp1e.com").unwrap();
593
594 assert_ne!(dn1, dn2);
595 assert_ne!(dn1, dn3);
596 assert_ne!(dn2, dn3);
597 }
598
599 #[test]
600 fn test_eq_str() {
601 let dn1 = Name::from("example.com").unwrap();
602 let dn2 = Name::from("EXAMPLE.COM").unwrap();
603
604 assert_eq!(dn1, "EXAMPLE.COM.");
605 assert_eq!(dn1, "EXAMPLE.COM");
606
607 assert_eq!(dn1, "eXaMpLe.cOm.");
608 assert_eq!(dn2, "eXaMpLe.cOm");
609
610 assert_eq!(dn2, "eXaMpLe.cOm");
611 assert_eq!(dn2, "eXaMpLe.cOm.");
612
613 assert_eq!(Name::from("sub.example.com").unwrap(), "sub.example.com.");
614 assert_eq!(Name::from("sub.example.com.").unwrap(), "sub.example.com");
615
616 assert_eq!(Name::new(), "");
617 assert_eq!(Name::root(), ".");
618 }
619
620 #[test]
621 fn test_neq_str() {
622 let dn1 = Name::from("example.com").unwrap();
623 let dn2 = Name::from("sub.example.com").unwrap();
624
625 assert_ne!(dn1, "sub.example.com");
626 assert_ne!(dn1, "sub.example.com.");
627
628 assert_ne!(dn1, "Sub.examp1e.com");
629 assert_ne!(dn1, "Sub.examp1e.com.");
630
631 assert_ne!(dn2, "Sub.examp1e.com");
632 assert_ne!(dn2, "Sub.examp1e.com.");
633
634 assert_ne!(Name::new(), ".");
635 assert_ne!(Name::root(), "");
636 }
637
638 #[test]
639 fn test_hash() {
640 let dn = Name::from("example.com").unwrap();
641
642 let mut s = HashSet::new();
643 s.insert(dn);
644
645 assert!(s.contains(&Name::from("example.com.").unwrap()));
646 assert!(s.contains(&Name::from("eXaMpLe.COM").unwrap()));
647 assert!(s.contains(&Name::from("EXAMPLE.COM").unwrap()));
648
649 assert!(!s.contains(&Name::from("suB.Example.com.").unwrap()));
650 }
651
652 #[test]
653 fn test_ord() {
654 let dn1 = Name::from("example.com").unwrap();
655 let dn2 = Name::from("ExaMplE.com").unwrap();
656 let dn3 = Name::from("Sub.example.com").unwrap();
657
658 assert_eq!(Ordering::Equal, dn1.cmp(&dn2));
659 assert_eq!(Ordering::Less, dn1.cmp(&dn3));
660 assert_eq!(Ordering::Greater, dn3.cmp(&dn1));
661 assert_eq!(Ordering::Equal, Name::root().cmp(&Name::root()));
662 assert_eq!(Ordering::Equal, Name::new().cmp(&Name::new()));
663 }
664
665 #[test]
666 fn test_partial_ord() {
667 let dn1 = Name::from("example.com").unwrap();
668 let dn2 = Name::from("ExaMplE.com").unwrap();
669 let dn3 = Name::from("Sub.example.com").unwrap();
670
671 assert_eq!(Some(Ordering::Equal), dn1.partial_cmp(&dn2));
672 assert_eq!(Some(Ordering::Less), dn1.partial_cmp(&dn3));
673 assert_eq!(Some(Ordering::Greater), dn3.partial_cmp(&dn1));
674 assert_eq!(
675 Some(Ordering::Equal),
676 Name::root().partial_cmp(&Name::root())
677 );
678 assert_eq!(Some(Ordering::Equal), Name::new().partial_cmp(&Name::new()));
679 }
680}