1use super::super::scan::{Symbol, SymbolCharsError, Symbols};
7use super::dname::Dname;
8use super::relative::{RelativeDname, RelativeDnameError};
9use super::traits::{ToDname, ToRelativeDname};
10use super::Label;
11#[cfg(feature = "bytes")]
12use bytes::BytesMut;
13use core::fmt;
14use octseq::builder::{EmptyBuilder, FreezeBuilder, OctetsBuilder, ShortBuf};
15#[cfg(feature = "std")]
16use std::vec::Vec;
17
18#[derive(Clone)]
37pub struct DnameBuilder<Builder> {
38 builder: Builder,
40
41 head: Option<usize>,
45}
46
47impl<Builder> DnameBuilder<Builder> {
48 pub(super) unsafe fn from_builder_unchecked(builder: Builder) -> Self {
54 DnameBuilder {
55 builder,
56 head: None,
57 }
58 }
59
60 #[must_use]
62 pub fn new() -> Self
63 where
64 Builder: EmptyBuilder,
65 {
66 unsafe { DnameBuilder::from_builder_unchecked(Builder::empty()) }
67 }
68
69 #[must_use]
71 pub fn with_capacity(capacity: usize) -> Self
72 where
73 Builder: EmptyBuilder,
74 {
75 unsafe {
76 DnameBuilder::from_builder_unchecked(Builder::with_capacity(
77 capacity,
78 ))
79 }
80 }
81
82 pub fn from_builder(builder: Builder) -> Result<Self, RelativeDnameError>
87 where
88 Builder: OctetsBuilder + AsRef<[u8]>,
89 {
90 RelativeDname::check_slice(builder.as_ref())?;
91 Ok(unsafe { DnameBuilder::from_builder_unchecked(builder) })
92 }
93}
94
95#[cfg(feature = "std")]
96impl DnameBuilder<Vec<u8>> {
97 #[must_use]
99 pub fn new_vec() -> Self {
100 Self::new()
101 }
102
103 #[must_use]
108 pub fn vec_with_capacity(capacity: usize) -> Self {
109 Self::with_capacity(capacity)
110 }
111}
112
113#[cfg(feature = "bytes")]
114impl DnameBuilder<BytesMut> {
115 pub fn new_bytes() -> Self {
117 Self::new()
118 }
119
120 pub fn bytes_with_capacity(capacity: usize) -> Self {
125 Self::with_capacity(capacity)
126 }
127}
128
129impl<Builder: AsRef<[u8]>> DnameBuilder<Builder> {
130 pub fn as_slice(&self) -> &[u8] {
132 self.builder.as_ref()
133 }
134
135 pub fn len(&self) -> usize {
137 self.builder.as_ref().len()
138 }
139
140 pub fn is_empty(&self) -> bool {
142 self.builder.as_ref().is_empty()
143 }
144}
145
146impl<Builder> DnameBuilder<Builder>
147where
148 Builder: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
149{
150 pub fn in_label(&self) -> bool {
157 self.head.is_some()
158 }
159
160 fn _append_slice(&mut self, slice: &[u8]) -> Result<(), PushError> {
165 self.builder
166 .append_slice(slice)
167 .map_err(|_| PushError::ShortBuf)
168 }
169
170 pub fn push(&mut self, ch: u8) -> Result<(), PushError> {
175 let len = self.len();
176 if len >= 254 {
177 return Err(PushError::LongName);
178 }
179 if let Some(head) = self.head {
180 if len - head > Label::MAX_LEN {
181 return Err(PushError::LongLabel);
182 }
183 self._append_slice(&[ch])?;
184 } else {
185 self.head = Some(len);
186 self._append_slice(&[0, ch])?;
187 }
188 Ok(())
189 }
190
191 pub fn push_symbol(&mut self, sym: Symbol) -> Result<(), FromStrError> {
196 if matches!(sym, Symbol::Char('.')) {
197 if !self.in_label() {
198 return Err(FromStrError::EmptyLabel);
199 }
200 self.end_label();
201 Ok(())
202 } else if matches!(sym, Symbol::SimpleEscape(b'['))
203 && !self.in_label()
204 {
205 Err(LabelFromStrError::BinaryLabel.into())
206 } else if let Ok(ch) = sym.into_octet() {
207 self.push(ch).map_err(Into::into)
208 } else {
209 return Err(match sym {
210 Symbol::Char(ch) => FromStrError::IllegalCharacter(ch),
211 _ => FromStrError::IllegalEscape,
212 });
213 }
214 }
215
216 pub fn append_slice(&mut self, slice: &[u8]) -> Result<(), PushError> {
223 if slice.is_empty() {
224 return Ok(());
225 }
226 if let Some(head) = self.head {
227 if slice.len() > Label::MAX_LEN - (self.len() - head) {
228 return Err(PushError::LongLabel);
229 }
230 } else {
231 if slice.len() > Label::MAX_LEN {
232 return Err(PushError::LongLabel);
233 }
234 if self.len() + slice.len() > 254 {
235 return Err(PushError::LongName);
236 }
237 self.head = Some(self.len());
238 self._append_slice(&[0])?;
239 }
240 self._append_slice(slice)?;
241 Ok(())
242 }
243
244 pub fn end_label(&mut self) {
248 if let Some(head) = self.head {
249 let len = self.len() - head - 1;
250 self.builder.as_mut()[head] = len as u8;
251 self.head = None;
252 }
253 }
254
255 pub fn append_label(&mut self, label: &[u8]) -> Result<(), PushError> {
264 let head = self.head;
265 self.end_label();
266 if let Err(err) = self.append_slice(label) {
267 self.head = head;
268 return Err(err);
269 }
270 self.end_label();
271 Ok(())
272 }
273
274 pub fn append_name<N: ToRelativeDname>(
284 &mut self,
285 name: &N,
286 ) -> Result<(), PushNameError> {
287 let head = self.head.take();
288 self.end_label();
289 if self.len() + usize::from(name.compose_len()) > 254 {
290 self.head = head;
291 return Err(PushNameError::LongName);
292 }
293 for label in name.iter_labels() {
294 label
295 .compose(&mut self.builder)
296 .map_err(|_| PushNameError::ShortBuf)?;
297 }
298 Ok(())
299 }
300
301 pub fn append_symbols<Sym: IntoIterator<Item = Symbol>>(
315 &mut self,
316 symbols: Sym,
317 ) -> Result<(), FromStrError> {
318 symbols
319 .into_iter()
320 .try_for_each(|symbol| self.push_symbol(symbol))
321 }
322
323 pub fn append_chars<C: IntoIterator<Item = char>>(
339 &mut self,
340 chars: C,
341 ) -> Result<(), FromStrError> {
342 Symbols::with(chars.into_iter(), |symbols| {
343 self.append_symbols(symbols)
344 })
345 }
346
347 pub fn finish(mut self) -> RelativeDname<Builder::Octets>
360 where
361 Builder: FreezeBuilder,
362 {
363 self.end_label();
364 unsafe { RelativeDname::from_octets_unchecked(self.builder.freeze()) }
365 }
366
367 pub fn into_dname(mut self) -> Result<Dname<Builder::Octets>, PushError>
373 where
374 Builder: FreezeBuilder,
375 {
376 self.end_label();
377 self._append_slice(&[0])?;
378 Ok(unsafe { Dname::from_octets_unchecked(self.builder.freeze()) })
379 }
380
381 pub fn append_origin<N: ToDname>(
388 mut self,
389 origin: &N,
390 ) -> Result<Dname<Builder::Octets>, PushNameError>
391 where
392 Builder: FreezeBuilder,
393 {
394 self.end_label();
395 if self.len() + usize::from(origin.compose_len()) > Dname::MAX_LEN {
396 return Err(PushNameError::LongName);
397 }
398 for label in origin.iter_labels() {
399 label
400 .compose(&mut self.builder)
401 .map_err(|_| PushNameError::ShortBuf)?;
402 }
403 Ok(unsafe { Dname::from_octets_unchecked(self.builder.freeze()) })
404 }
405}
406
407impl<Builder: EmptyBuilder> Default for DnameBuilder<Builder> {
410 fn default() -> Self {
411 Self::new()
412 }
413}
414
415impl<Builder: AsRef<[u8]>> AsRef<[u8]> for DnameBuilder<Builder> {
418 fn as_ref(&self) -> &[u8] {
419 self.builder.as_ref()
420 }
421}
422
423pub(super) fn parse_escape<C>(
429 chars: &mut C,
430 in_label: bool,
431) -> Result<u8, LabelFromStrError>
432where
433 C: Iterator<Item = char>,
434{
435 let ch = chars.next().ok_or(LabelFromStrError::UnexpectedEnd)?;
436 if ch.is_ascii_digit() {
437 let v = ch.to_digit(10).unwrap() * 100
438 + chars
439 .next()
440 .ok_or(LabelFromStrError::UnexpectedEnd)
441 .and_then(|c| {
442 c.to_digit(10).ok_or(LabelFromStrError::IllegalEscape)
443 })?
444 * 10
445 + chars
446 .next()
447 .ok_or(LabelFromStrError::UnexpectedEnd)
448 .and_then(|c| {
449 c.to_digit(10).ok_or(LabelFromStrError::IllegalEscape)
450 })?;
451 if v > 255 {
452 return Err(LabelFromStrError::IllegalEscape);
453 }
454 Ok(v as u8)
455 } else if ch == '[' {
456 if in_label {
459 Ok(b'[')
460 } else {
461 Err(LabelFromStrError::BinaryLabel)
462 }
463 } else {
464 Ok(ch as u8)
465 }
466}
467
468#[derive(Clone, Copy, Debug, Eq, PartialEq)]
474pub enum PushError {
475 LongLabel,
477
478 LongName,
480
481 ShortBuf,
483}
484
485impl From<ShortBuf> for PushError {
488 fn from(_: ShortBuf) -> PushError {
489 PushError::ShortBuf
490 }
491}
492
493impl fmt::Display for PushError {
496 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
497 match *self {
498 PushError::LongLabel => f.write_str("long label"),
499 PushError::LongName => f.write_str("long domain name"),
500 PushError::ShortBuf => ShortBuf.fmt(f),
501 }
502 }
503}
504
505#[cfg(feature = "std")]
506impl std::error::Error for PushError {}
507
508#[derive(Clone, Copy, Debug, Eq, PartialEq)]
512pub enum PushNameError {
513 LongName,
515
516 ShortBuf,
518}
519
520impl From<ShortBuf> for PushNameError {
523 fn from(_: ShortBuf) -> Self {
524 PushNameError::ShortBuf
525 }
526}
527
528impl fmt::Display for PushNameError {
531 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
532 match *self {
533 PushNameError::LongName => f.write_str("long domain name"),
534 PushNameError::ShortBuf => ShortBuf.fmt(f),
535 }
536 }
537}
538
539#[cfg(feature = "std")]
540impl std::error::Error for PushNameError {}
541
542#[derive(Clone, Copy, Debug, Eq, PartialEq)]
546pub enum LabelFromStrError {
547 UnexpectedEnd,
551
552 BinaryLabel,
554
555 LongLabel,
557
558 IllegalEscape,
564
565 IllegalCharacter(char),
569}
570
571impl fmt::Display for LabelFromStrError {
574 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
575 match *self {
576 LabelFromStrError::UnexpectedEnd => {
577 f.write_str("unexpected end of input")
578 }
579 LabelFromStrError::BinaryLabel => {
580 f.write_str("a binary label was encountered")
581 }
582 LabelFromStrError::LongLabel => {
583 f.write_str("label length limit exceeded")
584 }
585 LabelFromStrError::IllegalEscape => {
586 f.write_str("illegal escape sequence")
587 }
588 LabelFromStrError::IllegalCharacter(char) => {
589 write!(f, "illegal character '{}'", char)
590 }
591 }
592 }
593}
594
595#[cfg(feature = "std")]
596impl std::error::Error for LabelFromStrError {}
597
598#[derive(Clone, Copy, Debug, Eq, PartialEq)]
601#[non_exhaustive]
602pub enum FromStrError {
603 UnexpectedEnd,
607
608 EmptyLabel,
610
611 BinaryLabel,
613
614 LongLabel,
616
617 IllegalEscape,
623
624 IllegalCharacter(char),
628
629 LongName,
631
632 ShortBuf,
634}
635
636impl From<PushError> for FromStrError {
639 fn from(err: PushError) -> FromStrError {
640 match err {
641 PushError::LongLabel => FromStrError::LongLabel,
642 PushError::LongName => FromStrError::LongName,
643 PushError::ShortBuf => FromStrError::ShortBuf,
644 }
645 }
646}
647
648impl From<PushNameError> for FromStrError {
649 fn from(err: PushNameError) -> FromStrError {
650 match err {
651 PushNameError::LongName => FromStrError::LongName,
652 PushNameError::ShortBuf => FromStrError::ShortBuf,
653 }
654 }
655}
656
657impl From<LabelFromStrError> for FromStrError {
658 fn from(err: LabelFromStrError) -> FromStrError {
659 match err {
660 LabelFromStrError::UnexpectedEnd => FromStrError::UnexpectedEnd,
661 LabelFromStrError::BinaryLabel => FromStrError::BinaryLabel,
662 LabelFromStrError::LongLabel => FromStrError::LongLabel,
663 LabelFromStrError::IllegalEscape => FromStrError::IllegalEscape,
664 LabelFromStrError::IllegalCharacter(ch) => {
665 FromStrError::IllegalCharacter(ch)
666 }
667 }
668 }
669}
670
671impl From<SymbolCharsError> for FromStrError {
672 fn from(err: SymbolCharsError) -> FromStrError {
673 use crate::base::scan::SymbolCharsEnum;
674
675 match err.0 {
676 SymbolCharsEnum::BadEscape => Self::IllegalEscape,
677 SymbolCharsEnum::ShortInput => Self::UnexpectedEnd,
678 }
679 }
680}
681
682impl fmt::Display for FromStrError {
685 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
686 match *self {
687 FromStrError::UnexpectedEnd => {
688 f.write_str("unexpected end of input")
689 }
690 FromStrError::EmptyLabel => {
691 f.write_str("an empty label was encountered")
692 }
693 FromStrError::BinaryLabel => {
694 f.write_str("a binary label was encountered")
695 }
696 FromStrError::LongLabel => {
697 f.write_str("label length limit exceeded")
698 }
699 FromStrError::IllegalEscape => {
700 f.write_str("illegal escape sequence")
701 }
702 FromStrError::IllegalCharacter(char) => {
703 write!(f, "illegal character '{}'", char)
704 }
705 FromStrError::LongName => f.write_str("long domain name"),
706 FromStrError::ShortBuf => ShortBuf.fmt(f),
707 }
708 }
709}
710
711#[cfg(feature = "std")]
712impl std::error::Error for FromStrError {}
713
714#[cfg(test)]
717#[cfg(feature = "std")]
718mod test {
719 use super::*;
720
721 #[test]
722 fn compose() {
723 let mut builder = DnameBuilder::new_vec();
724 builder.push(b'w').unwrap();
725 builder.append_slice(b"ww").unwrap();
726 builder.end_label();
727 builder.append_slice(b"exa").unwrap();
728 builder.push(b'm').unwrap();
729 builder.push(b'p').unwrap();
730 builder.append_slice(b"le").unwrap();
731 builder.end_label();
732 builder.append_slice(b"com").unwrap();
733 assert_eq!(builder.finish().as_slice(), b"\x03www\x07example\x03com");
734 }
735
736 #[test]
737 fn build_by_label() {
738 let mut builder = DnameBuilder::new_vec();
739 builder.append_label(b"www").unwrap();
740 builder.append_label(b"example").unwrap();
741 builder.append_label(b"com").unwrap();
742 assert_eq!(builder.finish().as_slice(), b"\x03www\x07example\x03com");
743 }
744
745 #[test]
746 fn build_mixed() {
747 let mut builder = DnameBuilder::new_vec();
748 builder.push(b'w').unwrap();
749 builder.append_slice(b"ww").unwrap();
750 builder.append_label(b"example").unwrap();
751 builder.append_slice(b"com").unwrap();
752 assert_eq!(builder.finish().as_slice(), b"\x03www\x07example\x03com");
753 }
754
755 #[test]
756 fn name_limit() {
757 let mut builder = DnameBuilder::new_vec();
758 for _ in 0..25 {
759 builder.append_label(b"123456789").unwrap();
761 }
762
763 assert_eq!(builder.append_label(b"12345"), Err(PushError::LongName));
764 assert_eq!(builder.clone().append_label(b"1234"), Ok(()));
765
766 assert_eq!(builder.append_slice(b"12345"), Err(PushError::LongName));
767 assert_eq!(builder.clone().append_slice(b"1234"), Ok(()));
768
769 assert_eq!(builder.append_slice(b"12"), Ok(()));
770 assert_eq!(builder.push(b'3'), Ok(()));
771 assert_eq!(builder.push(b'4'), Err(PushError::LongName))
772 }
773
774 #[test]
775 fn label_limit() {
776 let mut builder = DnameBuilder::new_vec();
777 builder.append_label(&[0u8; 63][..]).unwrap();
778 assert_eq!(
779 builder.append_label(&[0u8; 64][..]),
780 Err(PushError::LongLabel)
781 );
782 assert_eq!(
783 builder.append_label(&[0u8; 164][..]),
784 Err(PushError::LongLabel)
785 );
786
787 builder.append_slice(&[0u8; 60][..]).unwrap();
788 builder.clone().append_label(b"123").unwrap();
789 assert_eq!(builder.append_slice(b"1234"), Err(PushError::LongLabel));
790 builder.append_slice(b"12").unwrap();
791 builder.push(b'3').unwrap();
792 assert_eq!(builder.push(b'4'), Err(PushError::LongLabel));
793 }
794
795 #[test]
796 fn finish() {
797 let mut builder = DnameBuilder::new_vec();
798 builder.append_label(b"www").unwrap();
799 builder.append_label(b"example").unwrap();
800 builder.append_slice(b"com").unwrap();
801 assert_eq!(builder.finish().as_slice(), b"\x03www\x07example\x03com");
802 }
803
804 #[test]
805 fn into_dname() {
806 let mut builder = DnameBuilder::new_vec();
807 builder.append_label(b"www").unwrap();
808 builder.append_label(b"example").unwrap();
809 builder.append_slice(b"com").unwrap();
810 assert_eq!(
811 builder.into_dname().unwrap().as_slice(),
812 b"\x03www\x07example\x03com\x00"
813 );
814 }
815}