domain_core/bits/name/
builder.rs1use bytes::{BufMut, BytesMut};
7use super::dname::Dname;
8use super::relative::RelativeDname;
9use super::traits::{ToDname, ToRelativeDname};
10
11
12#[derive(Clone)]
27pub struct DnameBuilder {
28 bytes: BytesMut,
30
31 head: Option<usize>,
35}
36
37impl DnameBuilder {
38 pub(super) unsafe fn from_bytes(bytes: BytesMut) -> Self {
44 DnameBuilder { bytes, head: None }
45 }
46
47 pub fn new() -> Self {
54 unsafe {
55 DnameBuilder::from_bytes(BytesMut::new())
56 }
57 }
58
59 pub fn with_capacity(capacity: usize) -> Self {
64 unsafe {
65 DnameBuilder::from_bytes(BytesMut::with_capacity(capacity))
66 }
67 }
68
69 pub fn len(&self) -> usize {
71 self.bytes.len()
72 }
73
74 pub fn is_empty(&self) -> bool {
76 self.bytes.is_empty()
77 }
78
79 pub fn capacity(&self) -> usize {
84 self.bytes.capacity()
85 }
86
87 pub fn in_label(&self) -> bool {
94 self.head.is_some()
95 }
96
97 pub fn push(&mut self, ch: u8) -> Result<(), PushError> {
102 let len = self.bytes.len();
103 if len >= 254 {
104 return Err(PushError::LongName);
105 }
106 if let Some(head) = self.head {
107 if len - head > 63 {
108 return Err(PushError::LongLabel)
109 }
110 self.ensure_capacity(1);
111 }
112 else {
113 self.head = Some(len);
114 self.ensure_capacity(2);
115 self.bytes.put_u8(0)
116 }
117 self.bytes.put_u8(ch);
118 Ok(())
119 }
120
121 pub fn append<T: AsRef<[u8]>>(&mut self, bytes: T)
128 -> Result<(), PushError> {
129 let bytes = bytes.as_ref();
130 if bytes.is_empty() {
131 return Ok(())
132 }
133 if let Some(head) = self.head {
134 if bytes.len() > 63 - (self.bytes.len() - head) {
135 return Err(PushError::LongLabel)
136 }
137 }
138 else {
139 if bytes.len() > 63 {
140 return Err(PushError::LongLabel)
141 }
142 if self.bytes.len() + bytes.len() > 254 {
143 return Err(PushError::LongName)
144 }
145 self.head = Some(self.bytes.len());
146 self.ensure_capacity(1);
147 self.bytes.put_u8(0)
148 }
149 self.ensure_capacity(bytes.len());
150 self.bytes.put_slice(bytes);
151 Ok(())
152 }
153
154 fn ensure_capacity(&mut self, additional: usize) {
161 if self.bytes.remaining_mut() < additional {
162 let additional = 255 - self.bytes.len();
163 self.bytes.reserve(additional)
164 }
165 }
166
167 pub fn end_label(&mut self) {
171 if let Some(head) = self.head {
172 let len = self.bytes.len() - head - 1;
173 self.bytes[head] = len as u8;
174 self.head = None;
175 }
176 }
177
178 pub fn append_label<T: AsRef<[u8]>>(&mut self, label: T)
187 -> Result<(), PushError> {
188 let head = self.head;
189 self.end_label();
190 if let Err(err) = self.append(label) {
191 self.head = head;
192 return Err(err)
193 }
194 self.end_label();
195 Ok(())
196 }
197
198 pub fn append_name<N: ToRelativeDname>(&mut self, name: &N)
208 -> Result<(), PushNameError> {
209 let head = self.head.take();
210 self.end_label();
211 if self.bytes.len() + name.compose_len() > 254 {
212 self.head = head;
213 return Err(PushNameError)
214 }
215 self.ensure_capacity(name.compose_len());
216 name.compose(&mut self.bytes);
217 Ok(())
218 }
219
220 pub fn finish(mut self) -> RelativeDname {
228 self.end_label();
229 unsafe { RelativeDname::from_bytes_unchecked(self.bytes.freeze()) }
230 }
231
232 pub fn into_dname(mut self) -> Result<Dname, PushNameError> {
243 self.end_label();
244 if self.bytes.len() >= 255 {
245 Err(PushNameError)
246 }
247 else {
248 self.ensure_capacity(1);
249 self.bytes.put_u8(0);
250 Ok(unsafe { Dname::from_bytes_unchecked(self.bytes.freeze()) })
251 }
252 }
253
254 pub fn append_origin<N: ToDname>(mut self, origin: &N)
261 -> Result<Dname, PushNameError> {
262 self.end_label();
263 if self.bytes.len() + origin.compose_len() > 255 {
264 return Err(PushNameError)
265 }
266 self.ensure_capacity(origin.compose_len());
267 origin.compose(&mut self.bytes);
268 Ok(unsafe { Dname::from_bytes_unchecked(self.bytes.freeze()) })
269 }
270}
271
272
273impl Default for DnameBuilder {
276 fn default() -> Self {
277 Self::new()
278 }
279}
280
281
282#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
286pub enum PushError {
287 #[fail(display="long label")]
289 LongLabel,
290
291 #[fail(display="long domain name")]
293 LongName,
294}
295
296
297#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
301#[fail(display="long domain name")]
302pub struct PushNameError;
303
304
305#[cfg(test)]
308mod test {
309 use super::*;
310
311 #[test]
312 fn build() {
313 let mut builder = DnameBuilder::with_capacity(255);
314 builder.push(b'w').unwrap();
315 builder.append(b"ww").unwrap();
316 builder.end_label();
317 builder.append(b"exa").unwrap();
318 builder.push(b'm').unwrap();
319 builder.push(b'p').unwrap();
320 builder.append(b"le").unwrap();
321 builder.end_label();
322 builder.append(b"com").unwrap();
323 assert_eq!(builder.finish().as_slice(),
324 b"\x03www\x07example\x03com");
325 }
326
327 #[test]
328 fn build_by_label() {
329 let mut builder = DnameBuilder::with_capacity(255);
330 builder.append_label(b"www").unwrap();
331 builder.append_label(b"example").unwrap();
332 builder.append_label(b"com").unwrap();
333 assert_eq!(builder.finish().as_slice(),
334 b"\x03www\x07example\x03com");
335 }
336
337 #[test]
338 fn build_mixed() {
339 let mut builder = DnameBuilder::with_capacity(255);
340 builder.push(b'w').unwrap();
341 builder.append(b"ww").unwrap();
342 builder.append_label(b"example").unwrap();
343 builder.append(b"com").unwrap();
344 assert_eq!(builder.finish().as_slice(),
345 b"\x03www\x07example\x03com");
346 }
347
348 #[test]
349 fn buf_growth() {
350 let mut builder = DnameBuilder::new();
351 builder.append_label(b"1234567890").unwrap();
352 builder.append_label(b"1234567890").unwrap();
353 builder.append_label(b"1234567890").unwrap();
354 builder.append_label(b"1234567890").unwrap();
355 assert!(builder.capacity() >= 255 && builder.capacity() < 1024);
356 assert_eq!(
357 builder.finish().as_slice(),
358 &b"\x0a1234567890\x0a1234567890\x0a1234567890\x0a1234567890"[..]
359 );
360 }
361
362 #[test]
363 fn name_limit() {
364 let mut builder = DnameBuilder::new();
365 for _ in 0..25 {
366 builder.append_label(b"123456789").unwrap();
368 }
369
370 assert_eq!(builder.append_label(b"12345"), Err(PushError::LongName));
371 assert_eq!(builder.clone().append_label(b"1234"), Ok(()));
372
373 assert_eq!(builder.append(b"12345"), Err(PushError::LongName));
374 assert_eq!(builder.clone().append(b"1234"), Ok(()));
375
376 assert_eq!(builder.append(b"12"), Ok(()));
377 assert_eq!(builder.push(b'3'), Ok(()));
378 assert_eq!(builder.push(b'4'), Err(PushError::LongName))
379 }
380
381 #[test]
382 fn label_limit() {
383 let mut builder = DnameBuilder::new();
384 builder.append_label(&[0u8; 63][..]).unwrap();
385 assert_eq!(builder.append_label(&[0u8; 64][..]),
386 Err(PushError::LongLabel));
387 assert_eq!(builder.append_label(&[0u8; 164][..]),
388 Err(PushError::LongLabel));
389
390 builder.append(&[0u8; 60][..]).unwrap();
391 let _ = builder.clone().append_label(b"123").unwrap();
392 assert_eq!(builder.append(b"1234"), Err(PushError::LongLabel));
393 builder.append(b"12").unwrap();
394 builder.push(b'3').unwrap();
395 assert_eq!(builder.push(b'4'), Err(PushError::LongLabel));
396 }
397
398 #[test]
399 fn finish() {
400 let mut builder = DnameBuilder::new();
401 builder.append_label(b"www").unwrap();
402 builder.append_label(b"example").unwrap();
403 builder.append(b"com").unwrap();
404 assert_eq!(builder.finish().as_slice(),
405 b"\x03www\x07example\x03com");
406 }
407
408 #[test]
409 fn into_dname() {
410 let mut builder = DnameBuilder::new();
411 builder.append_label(b"www").unwrap();
412 builder.append_label(b"example").unwrap();
413 builder.append(b"com").unwrap();
414 assert_eq!(builder.into_dname().unwrap().as_slice(),
415 b"\x03www\x07example\x03com\x00");
416 }
417
418 #[test]
419 fn into_dname_limit() {
420 let mut builder = DnameBuilder::new();
421 for _ in 0..51 {
422 builder.append_label(b"1234").unwrap();
423 }
424 assert_eq!(builder.len(), 255);
425 assert_eq!(builder.into_dname(), Err(PushNameError));
426 }
427}
428