#![cfg_attr(feature = "std", doc = "```")]
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
use super::header::{CountOverflow, Header, HeaderCounts, HeaderSection};
#[cfg(feature = "rand")]
use super::iana::Rtype;
use super::iana::{OptRcode, OptionCode, Rcode};
use super::message::Message;
use super::name::{Label, ToName};
use super::opt::{ComposeOptData, OptHeader, OptRecord};
use super::question::ComposeQuestion;
use super::record::ComposeRecord;
use super::wire::{Compose, Composer};
#[cfg(feature = "bytes")]
use bytes::BytesMut;
use core::ops::{Deref, DerefMut};
use core::{fmt, mem};
#[cfg(feature = "std")]
use hashbrown::HashTable;
#[cfg(feature = "std")]
use octseq::array::Array;
#[cfg(any(feature = "std", feature = "bytes"))]
use octseq::builder::infallible;
use octseq::builder::{FreezeBuilder, OctetsBuilder, ShortBuf, Truncate};
use octseq::octets::Octets;
#[cfg(feature = "std")]
use std::collections::{hash_map::RandomState, HashMap};
#[cfg(feature = "std")]
use std::hash::BuildHasher;
#[cfg(feature = "std")]
use std::vec::Vec;
#[derive(Clone, Debug)]
pub struct MessageBuilder<Target> {
target: Target,
limit: usize,
}
impl<Target: OctetsBuilder + Truncate> MessageBuilder<Target> {
pub fn from_target(
mut target: Target,
) -> Result<Self, Target::AppendError> {
target.truncate(0);
target.append_slice(HeaderSection::new().as_slice())?;
Ok(MessageBuilder {
target,
limit: usize::MAX,
})
}
}
#[cfg(feature = "std")]
impl MessageBuilder<Vec<u8>> {
#[must_use]
pub fn new_vec() -> Self {
infallible(Self::from_target(Vec::new()))
}
}
#[cfg(feature = "std")]
impl MessageBuilder<StreamTarget<Vec<u8>>> {
#[must_use]
pub fn new_stream_vec() -> Self {
Self::from_target(StreamTarget::new_vec()).unwrap()
}
}
#[cfg(feature = "bytes")]
impl MessageBuilder<BytesMut> {
pub fn new_bytes() -> Self {
infallible(Self::from_target(BytesMut::new()))
}
}
#[cfg(feature = "bytes")]
impl MessageBuilder<StreamTarget<BytesMut>> {
pub fn new_stream_bytes() -> Self {
Self::from_target(StreamTarget::new_bytes()).unwrap()
}
}
impl<Target: Composer> MessageBuilder<Target> {
pub fn start_answer<Octs: Octets + ?Sized>(
mut self,
msg: &Message<Octs>,
rcode: Rcode,
) -> Result<AnswerBuilder<Target>, PushError> {
{
let header = self.header_mut();
header.set_id(msg.header().id());
header.set_qr(true);
header.set_opcode(msg.header().opcode());
header.set_rd(msg.header().rd());
header.set_rcode(rcode);
}
let mut builder = self.question();
for item in msg.question().flatten() {
builder.push(item)?;
}
Ok(builder.answer())
}
pub fn start_error<Octs: Octets + ?Sized>(
mut self,
msg: &Message<Octs>,
rcode: Rcode,
) -> AnswerBuilder<Target> {
{
let header = self.header_mut();
header.set_id(msg.header().id());
header.set_qr(true);
header.set_opcode(msg.header().opcode());
header.set_rd(msg.header().rd());
header.set_rcode(rcode);
}
let mut builder = self.question();
for item in msg.question().flatten() {
if builder.push(item).is_err() {
builder.header_mut().set_rcode(Rcode::SERVFAIL);
break;
}
}
builder.answer()
}
#[cfg(feature = "rand")]
pub fn request_axfr<N: ToName>(
mut self,
apex: N,
) -> Result<AnswerBuilder<Target>, PushError> {
self.header_mut().set_random_id();
let mut builder = self.question();
builder.push((apex, Rtype::AXFR))?;
Ok(builder.answer())
}
}
impl<Target: Composer> MessageBuilder<Target> {
pub fn set_push_limit(&mut self, limit: usize) {
self.limit = limit;
}
pub fn clear_push_limit(&mut self) {
self.limit = usize::MAX;
}
pub fn push_limit(&self) -> Option<usize> {
if self.limit == usize::MAX {
None
} else {
Some(self.limit)
}
}
}
impl<Target: OctetsBuilder + AsRef<[u8]>> MessageBuilder<Target> {
pub fn header(&self) -> Header {
*Header::for_message_slice(self.target.as_ref())
}
pub fn counts(&self) -> HeaderCounts {
*HeaderCounts::for_message_slice(self.target.as_ref())
}
}
impl<Target: OctetsBuilder + AsMut<[u8]>> MessageBuilder<Target> {
pub fn header_mut(&mut self) -> &mut Header {
Header::for_message_slice_mut(self.target.as_mut())
}
fn counts_mut(&mut self) -> &mut HeaderCounts {
HeaderCounts::for_message_slice_mut(self.target.as_mut())
}
}
impl<Target> MessageBuilder<Target> {
pub fn builder(self) -> MessageBuilder<Target> {
self
}
}
impl<Target: Composer> MessageBuilder<Target> {
pub fn question(self) -> QuestionBuilder<Target> {
QuestionBuilder::new(self)
}
pub fn answer(self) -> AnswerBuilder<Target> {
self.question().answer()
}
pub fn authority(self) -> AuthorityBuilder<Target> {
self.question().answer().authority()
}
pub fn additional(self) -> AdditionalBuilder<Target> {
self.question().answer().authority().additional()
}
pub fn finish(self) -> Target {
self.target
}
}
impl<Target: FreezeBuilder> MessageBuilder<Target> {
pub fn into_message(self) -> Message<Target::Octets> {
unsafe { Message::from_octets_unchecked(self.target.freeze()) }
}
}
impl<Target> MessageBuilder<Target> {
pub fn as_target(&self) -> &Target {
&self.target
}
fn as_target_mut(&mut self) -> &mut Target {
&mut self.target
}
pub fn as_slice(&self) -> &[u8]
where
Target: AsRef<[u8]>,
{
self.as_target().as_ref()
}
pub fn as_message(&self) -> Message<&[u8]>
where
Target: AsRef<[u8]>,
{
unsafe { Message::from_octets_unchecked(self.target.as_ref()) }
}
}
impl<Target: Composer> MessageBuilder<Target> {
fn push<Push, Inc>(
&mut self,
push: Push,
inc: Inc,
) -> Result<(), PushError>
where
Push: FnOnce(&mut Target) -> Result<(), ShortBuf>,
Inc: FnOnce(&mut HeaderCounts) -> Result<(), CountOverflow>,
{
let pos = self.target.as_ref().len();
if let Err(err) = push(&mut self.target) {
self.target.truncate(pos);
return Err(From::from(err));
}
let new_pos = self.target.as_ref().len();
if new_pos >= self.limit {
self.target.truncate(pos);
return Err(PushError::LimitExceeded);
}
if inc(self.counts_mut()).is_err() {
self.target.truncate(pos);
return Err(PushError::CountOverflow);
}
Ok(())
}
}
impl<Target> From<QuestionBuilder<Target>> for MessageBuilder<Target>
where
Target: Composer,
{
fn from(src: QuestionBuilder<Target>) -> Self {
src.builder()
}
}
impl<Target> From<AnswerBuilder<Target>> for MessageBuilder<Target>
where
Target: Composer,
{
fn from(src: AnswerBuilder<Target>) -> Self {
src.builder()
}
}
impl<Target> From<AuthorityBuilder<Target>> for MessageBuilder<Target>
where
Target: Composer,
{
fn from(src: AuthorityBuilder<Target>) -> Self {
src.builder()
}
}
impl<Target> From<AdditionalBuilder<Target>> for MessageBuilder<Target>
where
Target: Composer,
{
fn from(src: AdditionalBuilder<Target>) -> Self {
src.builder()
}
}
impl<Target> From<MessageBuilder<Target>> for Message<Target::Octets>
where
Target: FreezeBuilder,
{
fn from(src: MessageBuilder<Target>) -> Self {
src.into_message()
}
}
impl<Target> AsRef<Target> for MessageBuilder<Target> {
fn as_ref(&self) -> &Target {
self.as_target()
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for MessageBuilder<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
#[derive(Clone, Debug)]
pub struct QuestionBuilder<Target> {
builder: MessageBuilder<Target>,
}
impl<Target: OctetsBuilder> QuestionBuilder<Target> {
fn new(builder: MessageBuilder<Target>) -> Self {
Self { builder }
}
}
impl<Target: Composer> QuestionBuilder<Target> {
#[cfg_attr(feature = "std", doc = "```")]
#[cfg_attr(not(feature = "std"), doc = "```ignore")]
pub fn push(
&mut self,
question: impl ComposeQuestion,
) -> Result<(), PushError> {
self.builder.push(
|target| question.compose_question(target).map_err(Into::into),
|counts| counts.inc_qdcount(),
)
}
}
impl<Target: Composer> QuestionBuilder<Target> {
pub fn rewind(&mut self) {
self.as_target_mut()
.truncate(mem::size_of::<HeaderSection>());
self.counts_mut().set_qdcount(0);
}
pub fn builder(mut self) -> MessageBuilder<Target> {
self.rewind();
self.builder
}
}
impl<Target> QuestionBuilder<Target> {
pub fn question(self) -> QuestionBuilder<Target> {
self
}
}
impl<Target: Composer> QuestionBuilder<Target> {
pub fn answer(self) -> AnswerBuilder<Target> {
AnswerBuilder::new(self.builder)
}
pub fn authority(self) -> AuthorityBuilder<Target> {
self.answer().authority()
}
pub fn additional(self) -> AdditionalBuilder<Target> {
self.answer().authority().additional()
}
pub fn finish(self) -> Target {
self.builder.finish()
}
}
impl<Target: FreezeBuilder> QuestionBuilder<Target> {
pub fn into_message(self) -> Message<Target::Octets> {
self.builder.into_message()
}
}
impl<Target> QuestionBuilder<Target> {
pub fn as_builder(&self) -> &MessageBuilder<Target> {
&self.builder
}
pub fn as_builder_mut(&mut self) -> &mut MessageBuilder<Target> {
&mut self.builder
}
}
impl<Target> From<MessageBuilder<Target>> for QuestionBuilder<Target>
where
Target: Composer,
{
fn from(src: MessageBuilder<Target>) -> Self {
src.question()
}
}
impl<Target> From<AnswerBuilder<Target>> for QuestionBuilder<Target>
where
Target: Composer,
{
fn from(src: AnswerBuilder<Target>) -> Self {
src.question()
}
}
impl<Target> From<AuthorityBuilder<Target>> for QuestionBuilder<Target>
where
Target: Composer,
{
fn from(src: AuthorityBuilder<Target>) -> Self {
src.question()
}
}
impl<Target> From<AdditionalBuilder<Target>> for QuestionBuilder<Target>
where
Target: Composer,
{
fn from(src: AdditionalBuilder<Target>) -> Self {
src.question()
}
}
impl<Target> From<QuestionBuilder<Target>> for Message<Target::Octets>
where
Target: FreezeBuilder,
{
fn from(src: QuestionBuilder<Target>) -> Self {
src.into_message()
}
}
impl<Target> Deref for QuestionBuilder<Target> {
type Target = MessageBuilder<Target>;
fn deref(&self) -> &Self::Target {
&self.builder
}
}
impl<Target> DerefMut for QuestionBuilder<Target> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.builder
}
}
impl<Target> AsRef<MessageBuilder<Target>> for QuestionBuilder<Target> {
fn as_ref(&self) -> &MessageBuilder<Target> {
self.as_builder()
}
}
impl<Target> AsMut<MessageBuilder<Target>> for QuestionBuilder<Target> {
fn as_mut(&mut self) -> &mut MessageBuilder<Target> {
self.as_builder_mut()
}
}
impl<Target> AsRef<Target> for QuestionBuilder<Target> {
fn as_ref(&self) -> &Target {
self.as_target()
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for QuestionBuilder<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
#[derive(Clone, Debug)]
pub struct AnswerBuilder<Target> {
builder: MessageBuilder<Target>,
start: usize,
}
impl<Target: Composer> AnswerBuilder<Target> {
#[must_use]
fn new(builder: MessageBuilder<Target>) -> Self {
AnswerBuilder {
start: builder.target.as_ref().len(),
builder,
}
}
}
impl<Target> AnswerBuilder<Target> {
#[must_use]
pub fn into_target(self) -> Target {
self.builder.target
}
}
impl<Target: Composer> AnswerBuilder<Target> {
#[cfg_attr(feature = "std", doc = "```")]
#[cfg_attr(not(feature = "std"), doc = "```ignore")]
pub fn push(
&mut self,
record: impl ComposeRecord,
) -> Result<(), PushError> {
self.builder.push(
|target| record.compose_record(target).map_err(Into::into),
|counts| counts.inc_ancount(),
)
}
pub fn push_ref(
&mut self,
record: &impl ComposeRecord,
) -> Result<(), PushError> {
self.builder.push(
|target| record.compose_record(target).map_err(Into::into),
|counts| counts.inc_ancount(),
)
}
}
impl<Target: Composer> AnswerBuilder<Target> {
pub fn rewind(&mut self) {
self.builder.target.truncate(self.start);
self.counts_mut().set_ancount(0);
}
pub fn builder(self) -> MessageBuilder<Target> {
self.question().builder()
}
pub fn question(mut self) -> QuestionBuilder<Target> {
self.rewind();
QuestionBuilder::new(self.builder)
}
}
impl<Target: Composer> AnswerBuilder<Target> {
pub fn answer(self) -> AnswerBuilder<Target> {
self
}
pub fn authority(self) -> AuthorityBuilder<Target> {
AuthorityBuilder::new(self)
}
pub fn additional(self) -> AdditionalBuilder<Target> {
self.authority().additional()
}
pub fn finish(self) -> Target {
self.builder.finish()
}
}
impl<Target: FreezeBuilder> AnswerBuilder<Target> {
pub fn into_message(self) -> Message<Target::Octets> {
self.builder.into_message()
}
}
impl<Target> AnswerBuilder<Target> {
pub fn as_builder(&self) -> &MessageBuilder<Target> {
&self.builder
}
pub fn as_builder_mut(&mut self) -> &mut MessageBuilder<Target> {
&mut self.builder
}
}
impl<Target> From<MessageBuilder<Target>> for AnswerBuilder<Target>
where
Target: Composer,
{
fn from(src: MessageBuilder<Target>) -> Self {
src.answer()
}
}
impl<Target> From<QuestionBuilder<Target>> for AnswerBuilder<Target>
where
Target: Composer,
{
fn from(src: QuestionBuilder<Target>) -> Self {
src.answer()
}
}
impl<Target> From<AuthorityBuilder<Target>> for AnswerBuilder<Target>
where
Target: Composer,
{
fn from(src: AuthorityBuilder<Target>) -> Self {
src.answer()
}
}
impl<Target> From<AdditionalBuilder<Target>> for AnswerBuilder<Target>
where
Target: Composer,
{
fn from(src: AdditionalBuilder<Target>) -> Self {
src.answer()
}
}
impl<Target> From<AnswerBuilder<Target>> for Message<Target::Octets>
where
Target: FreezeBuilder,
{
fn from(src: AnswerBuilder<Target>) -> Self {
src.into_message()
}
}
impl<Target> Deref for AnswerBuilder<Target> {
type Target = MessageBuilder<Target>;
fn deref(&self) -> &Self::Target {
&self.builder
}
}
impl<Target> DerefMut for AnswerBuilder<Target> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.builder
}
}
impl<Target> AsRef<MessageBuilder<Target>> for AnswerBuilder<Target> {
fn as_ref(&self) -> &MessageBuilder<Target> {
self.as_builder()
}
}
impl<Target> AsMut<MessageBuilder<Target>> for AnswerBuilder<Target> {
fn as_mut(&mut self) -> &mut MessageBuilder<Target> {
self.as_builder_mut()
}
}
impl<Target> AsRef<Target> for AnswerBuilder<Target> {
fn as_ref(&self) -> &Target {
self.as_target()
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for AnswerBuilder<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
#[derive(Clone, Debug)]
pub struct AuthorityBuilder<Target> {
answer: AnswerBuilder<Target>,
start: usize,
}
impl<Target: Composer> AuthorityBuilder<Target> {
fn new(answer: AnswerBuilder<Target>) -> Self {
AuthorityBuilder {
start: answer.as_target().as_ref().len(),
answer,
}
}
}
impl<Target: Composer> AuthorityBuilder<Target> {
#[cfg_attr(feature = "std", doc = "```")]
#[cfg_attr(not(feature = "std"), doc = "```ignore")]
pub fn push(
&mut self,
record: impl ComposeRecord,
) -> Result<(), PushError> {
self.answer.builder.push(
|target| record.compose_record(target).map_err(Into::into),
|counts| counts.inc_nscount(),
)
}
}
impl<Target: Composer> AuthorityBuilder<Target> {
pub fn rewind(&mut self) {
self.answer.as_target_mut().truncate(self.start);
self.counts_mut().set_nscount(0);
}
pub fn builder(self) -> MessageBuilder<Target> {
self.question().builder()
}
pub fn question(self) -> QuestionBuilder<Target> {
self.answer().question()
}
pub fn answer(mut self) -> AnswerBuilder<Target> {
self.rewind();
self.answer
}
pub fn authority(self) -> AuthorityBuilder<Target> {
self
}
pub fn additional(self) -> AdditionalBuilder<Target> {
AdditionalBuilder::new(self)
}
pub fn finish(self) -> Target {
self.answer.finish()
}
}
impl<Target: FreezeBuilder> AuthorityBuilder<Target> {
pub fn into_message(self) -> Message<Target::Octets> {
self.answer.into_message()
}
}
impl<Target> AuthorityBuilder<Target> {
pub fn as_builder(&self) -> &MessageBuilder<Target> {
self.answer.as_builder()
}
pub fn as_builder_mut(&mut self) -> &mut MessageBuilder<Target> {
self.answer.as_builder_mut()
}
}
impl<Target> From<MessageBuilder<Target>> for AuthorityBuilder<Target>
where
Target: Composer,
{
fn from(src: MessageBuilder<Target>) -> Self {
src.authority()
}
}
impl<Target> From<QuestionBuilder<Target>> for AuthorityBuilder<Target>
where
Target: Composer,
{
fn from(src: QuestionBuilder<Target>) -> Self {
src.authority()
}
}
impl<Target> From<AnswerBuilder<Target>> for AuthorityBuilder<Target>
where
Target: Composer,
{
fn from(src: AnswerBuilder<Target>) -> Self {
src.authority()
}
}
impl<Target> From<AdditionalBuilder<Target>> for AuthorityBuilder<Target>
where
Target: Composer,
{
fn from(src: AdditionalBuilder<Target>) -> Self {
src.authority()
}
}
impl<Target> From<AuthorityBuilder<Target>> for Message<Target::Octets>
where
Target: FreezeBuilder,
{
fn from(src: AuthorityBuilder<Target>) -> Self {
src.into_message()
}
}
impl<Target> Deref for AuthorityBuilder<Target> {
type Target = MessageBuilder<Target>;
fn deref(&self) -> &Self::Target {
self.answer.deref()
}
}
impl<Target> DerefMut for AuthorityBuilder<Target> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.answer.deref_mut()
}
}
impl<Target> AsRef<MessageBuilder<Target>> for AuthorityBuilder<Target> {
fn as_ref(&self) -> &MessageBuilder<Target> {
self.as_builder()
}
}
impl<Target> AsMut<MessageBuilder<Target>> for AuthorityBuilder<Target> {
fn as_mut(&mut self) -> &mut MessageBuilder<Target> {
self.as_builder_mut()
}
}
impl<Target> AsRef<Target> for AuthorityBuilder<Target> {
fn as_ref(&self) -> &Target {
self.as_target()
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for AuthorityBuilder<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
#[derive(Clone, Debug)]
pub struct AdditionalBuilder<Target> {
authority: AuthorityBuilder<Target>,
start: usize,
}
impl<Target: Composer> AdditionalBuilder<Target> {
fn new(authority: AuthorityBuilder<Target>) -> Self {
AdditionalBuilder {
start: authority.as_target().as_ref().len(),
authority,
}
}
}
impl<Target: Composer> AdditionalBuilder<Target> {
#[cfg_attr(feature = "std", doc = "```")]
#[cfg_attr(not(feature = "std"), doc = "```ignore")]
pub fn push(
&mut self,
record: impl ComposeRecord,
) -> Result<(), PushError> {
self.authority.answer.builder.push(
|target| record.compose_record(target).map_err(Into::into),
|counts| counts.inc_arcount(),
)
}
}
impl<Target: Composer> AdditionalBuilder<Target> {
pub fn opt<F>(&mut self, op: F) -> Result<(), PushError>
where
F: FnOnce(
&mut OptBuilder<'_, Target>,
) -> Result<(), Target::AppendError>,
{
self.authority.answer.builder.push(
|target| OptBuilder::new(target)?.build(op),
|counts| counts.inc_arcount(),
)
}
}
impl<Target: Composer> AdditionalBuilder<Target> {
pub fn rewind(&mut self) {
self.authority.as_target_mut().truncate(self.start);
self.counts_mut().set_arcount(0);
}
pub fn builder(self) -> MessageBuilder<Target> {
self.question().builder()
}
pub fn question(self) -> QuestionBuilder<Target> {
self.answer().question()
}
pub fn answer(self) -> AnswerBuilder<Target> {
self.authority().answer()
}
pub fn authority(mut self) -> AuthorityBuilder<Target> {
self.rewind();
self.authority
}
pub fn additional(self) -> AdditionalBuilder<Target> {
self
}
pub fn finish(self) -> Target {
self.authority.finish()
}
}
impl<Target: FreezeBuilder> AdditionalBuilder<Target> {
pub fn into_message(self) -> Message<Target::Octets> {
self.authority.into_message()
}
}
impl<Target> AdditionalBuilder<Target> {
pub fn as_builder(&self) -> &MessageBuilder<Target> {
self.authority.as_builder()
}
pub fn as_builder_mut(&mut self) -> &mut MessageBuilder<Target> {
self.authority.as_builder_mut()
}
}
impl<Target> From<MessageBuilder<Target>> for AdditionalBuilder<Target>
where
Target: Composer,
{
fn from(src: MessageBuilder<Target>) -> Self {
src.additional()
}
}
impl<Target> From<QuestionBuilder<Target>> for AdditionalBuilder<Target>
where
Target: Composer,
{
fn from(src: QuestionBuilder<Target>) -> Self {
src.additional()
}
}
impl<Target> From<AnswerBuilder<Target>> for AdditionalBuilder<Target>
where
Target: Composer,
{
fn from(src: AnswerBuilder<Target>) -> Self {
src.additional()
}
}
impl<Target> From<AuthorityBuilder<Target>> for AdditionalBuilder<Target>
where
Target: Composer,
{
fn from(src: AuthorityBuilder<Target>) -> Self {
src.additional()
}
}
impl<Target> From<AdditionalBuilder<Target>> for Message<Target::Octets>
where
Target: FreezeBuilder,
{
fn from(src: AdditionalBuilder<Target>) -> Self {
src.into_message()
}
}
impl<Target> Deref for AdditionalBuilder<Target> {
type Target = MessageBuilder<Target>;
fn deref(&self) -> &Self::Target {
self.as_builder()
}
}
impl<Target> DerefMut for AdditionalBuilder<Target> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_builder_mut()
}
}
impl<Target> AsRef<MessageBuilder<Target>> for AdditionalBuilder<Target> {
fn as_ref(&self) -> &MessageBuilder<Target> {
self.as_builder()
}
}
impl<Target> AsMut<MessageBuilder<Target>> for AdditionalBuilder<Target> {
fn as_mut(&mut self) -> &mut MessageBuilder<Target> {
self.as_builder_mut()
}
}
impl<Target> AsRef<Target> for AdditionalBuilder<Target> {
fn as_ref(&self) -> &Target {
self.as_target()
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for AdditionalBuilder<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
pub trait RecordSectionBuilder<Target: Composer> {
fn push(&mut self, record: impl ComposeRecord) -> Result<(), PushError>;
}
impl<Target> RecordSectionBuilder<Target> for AnswerBuilder<Target>
where
Target: Composer,
{
fn push(&mut self, record: impl ComposeRecord) -> Result<(), PushError> {
Self::push(self, record)
}
}
impl<Target: Composer> RecordSectionBuilder<Target>
for AuthorityBuilder<Target>
{
fn push(&mut self, record: impl ComposeRecord) -> Result<(), PushError> {
Self::push(self, record)
}
}
impl<Target> RecordSectionBuilder<Target> for AdditionalBuilder<Target>
where
Target: Composer,
{
fn push(&mut self, record: impl ComposeRecord) -> Result<(), PushError> {
Self::push(self, record)
}
}
pub struct OptBuilder<'a, Target: ?Sized> {
start: usize,
target: &'a mut Target,
}
impl<'a, Target: Composer + ?Sized> OptBuilder<'a, Target> {
fn new(target: &'a mut Target) -> Result<Self, ShortBuf> {
let start = target.as_ref().len();
OptHeader::default().compose(target).map_err(Into::into)?;
Ok(OptBuilder { start, target })
}
fn build<F>(&mut self, op: F) -> Result<(), ShortBuf>
where
F: FnOnce(&mut Self) -> Result<(), Target::AppendError>,
{
self.target.append_slice(&[0; 2]).map_err(Into::into)?;
let pos = self.target.as_ref().len();
match op(self) {
Ok(_) => match u16::try_from(self.target.as_ref().len() - pos) {
Ok(len) => {
self.target.as_mut()[pos - 2..pos]
.copy_from_slice(&(len).to_be_bytes());
Ok(())
}
Err(_) => {
self.target.truncate(pos);
Err(ShortBuf)
}
},
Err(_) => {
self.target.truncate(pos);
Err(ShortBuf)
}
}
}
pub fn clone_from<T: AsRef<[u8]>>(
&mut self,
source: &OptRecord<T>,
) -> Result<(), Target::AppendError> {
self.target.truncate(self.start);
source.as_record().compose(self.target)
}
pub fn push<Opt: ComposeOptData + ?Sized>(
&mut self,
opt: &Opt,
) -> Result<(), Target::AppendError> {
self.push_raw_option(opt.code(), opt.compose_len(), |target| {
opt.compose_option(target)
})
}
pub fn push_raw_option<F>(
&mut self,
code: OptionCode,
option_len: u16,
op: F,
) -> Result<(), Target::AppendError>
where
F: FnOnce(&mut Target) -> Result<(), Target::AppendError>,
{
code.compose(self.target)?;
option_len.compose(self.target)?;
op(self.target)
}
#[must_use]
pub fn udp_payload_size(&self) -> u16 {
self.opt_header().udp_payload_size()
}
pub fn set_udp_payload_size(&mut self, value: u16) {
self.opt_header_mut().set_udp_payload_size(value)
}
#[must_use]
pub fn rcode(&self) -> OptRcode {
self.opt_header()
.rcode(*Header::for_message_slice(self.target.as_ref()))
}
pub fn set_rcode(&mut self, rcode: OptRcode) {
Header::for_message_slice_mut(self.target.as_mut())
.set_rcode(rcode.rcode());
self.opt_header_mut().set_rcode(rcode)
}
#[must_use]
pub fn version(&self) -> u8 {
self.opt_header().version()
}
pub fn set_version(&mut self, version: u8) {
self.opt_header_mut().set_version(version)
}
#[must_use]
pub fn dnssec_ok(&self) -> bool {
self.opt_header().dnssec_ok()
}
pub fn set_dnssec_ok(&mut self, value: bool) {
self.opt_header_mut().set_dnssec_ok(value)
}
fn opt_header(&self) -> &OptHeader {
OptHeader::for_record_slice(&self.target.as_ref()[self.start..])
}
fn opt_header_mut(&mut self) -> &mut OptHeader {
let start = self.start;
OptHeader::for_record_slice_mut(&mut self.target.as_mut()[start..])
}
pub fn as_target(&self) -> &Target {
self.target
}
}
#[derive(Clone, Debug, Default)]
pub struct StreamTarget<Target> {
target: Target,
}
impl<Target: Composer> StreamTarget<Target> {
pub fn new(mut target: Target) -> Result<Self, Target::AppendError> {
target.truncate(0);
0u16.compose(&mut target)?;
Ok(StreamTarget { target })
}
}
#[cfg(feature = "std")]
impl StreamTarget<Vec<u8>> {
#[must_use]
pub fn new_vec() -> Self {
infallible(Self::new(Vec::new()))
}
}
#[cfg(feature = "bytes")]
impl StreamTarget<BytesMut> {
pub fn new_bytes() -> Self {
infallible(Self::new(BytesMut::new()))
}
}
impl<Target> StreamTarget<Target> {
pub fn as_target(&self) -> &Target {
&self.target
}
pub fn into_target(self) -> Target {
self.target
}
}
impl<Target: AsRef<[u8]> + AsMut<[u8]>> StreamTarget<Target> {
fn update_shim(&mut self) -> Result<(), ShortBuf> {
match u16::try_from(self.target.as_ref().len() - 2) {
Ok(len) => {
self.target.as_mut()[..2].copy_from_slice(&len.to_be_bytes());
Ok(())
}
Err(_) => Err(ShortBuf),
}
}
}
impl<Target: AsRef<[u8]>> StreamTarget<Target> {
pub fn as_stream_slice(&self) -> &[u8] {
self.target.as_ref()
}
pub fn as_dgram_slice(&self) -> &[u8] {
&self.target.as_ref()[2..]
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for StreamTarget<Target> {
fn as_ref(&self) -> &[u8] {
&self.target.as_ref()[2..]
}
}
impl<Target: AsMut<[u8]>> AsMut<[u8]> for StreamTarget<Target> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.target.as_mut()[2..]
}
}
impl<Target> OctetsBuilder for StreamTarget<Target>
where
Target: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
Target::AppendError: Into<ShortBuf>,
{
type AppendError = ShortBuf;
fn append_slice(
&mut self,
slice: &[u8],
) -> Result<(), Self::AppendError> {
self.target.append_slice(slice).map_err(Into::into)?;
self.update_shim()
}
}
impl<Target: Composer> Truncate for StreamTarget<Target> {
fn truncate(&mut self, len: usize) {
self.target
.truncate(len.checked_add(2).expect("long truncate"));
self.update_shim().expect("truncate grew buffer???")
}
}
impl<Target> Composer for StreamTarget<Target>
where
Target: Composer,
Target::AppendError: Into<ShortBuf>,
{
fn append_compressed_name<N: ToName + ?Sized>(
&mut self,
name: &N,
) -> Result<(), Self::AppendError> {
self.target
.append_compressed_name(name)
.map_err(Into::into)?;
self.update_shim()
}
}
#[derive(Clone, Debug)]
pub struct StaticCompressor<Target> {
target: Target,
entries: [u16; 24],
len: usize,
}
impl<Target> StaticCompressor<Target> {
pub fn new(target: Target) -> Self {
StaticCompressor {
target,
entries: Default::default(),
len: 0,
}
}
pub fn as_target(&self) -> &Target {
&self.target
}
pub fn into_target(self) -> Target {
self.target
}
pub fn as_slice(&self) -> &[u8]
where
Target: AsRef<[u8]>,
{
self.target.as_ref()
}
pub fn as_slice_mut(&mut self) -> &mut [u8]
where
Target: AsMut<[u8]>,
{
self.target.as_mut()
}
fn get<'a, N: Iterator<Item = &'a Label> + Clone>(
&self,
name: N,
) -> Option<u16>
where
Target: AsRef<[u8]>,
{
self.entries[..self.len].iter().find_map(|&pos| {
if name
.clone()
.eq(Label::iter_slice(self.target.as_ref(), pos as usize))
{
Some(pos)
} else {
None
}
})
}
fn insert(&mut self, pos: usize) -> bool {
if pos < 0xc000 && self.len < self.entries.len() {
self.entries[self.len] = pos as u16;
self.len += 1;
true
} else {
false
}
}
}
impl<Target: AsRef<[u8]>> AsRef<[u8]> for StaticCompressor<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<Target: AsMut<[u8]>> AsMut<[u8]> for StaticCompressor<Target> {
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl<Target: OctetsBuilder> OctetsBuilder for StaticCompressor<Target> {
type AppendError = Target::AppendError;
fn append_slice(
&mut self,
slice: &[u8],
) -> Result<(), Self::AppendError> {
self.target.append_slice(slice)
}
}
impl<Target: Composer> Composer for StaticCompressor<Target> {
fn append_compressed_name<N: ToName + ?Sized>(
&mut self,
name: &N,
) -> Result<(), Self::AppendError> {
let mut name = name.iter_labels().peekable();
loop {
if let Some(label) = name.peek() {
if label.is_root() {
label.compose(self)?;
return Ok(());
}
}
if let Some(pos) = self.get(name.clone()) {
return (pos | 0xC000).compose(self);
}
if !self.insert(self.target.as_ref().len()) {
for label in &mut name {
label.compose(self)?;
}
return Ok(());
}
let label = name.next().unwrap();
label.compose(self)?;
}
}
fn can_compress(&self) -> bool {
true
}
}
impl<Target: Truncate> Truncate for StaticCompressor<Target> {
fn truncate(&mut self, len: usize) {
self.target.truncate(len);
if len < 0xC000 {
let len = len as u16;
for i in 0..self.len {
if self.entries[i] >= len {
self.len = i;
break;
}
}
}
}
}
impl<Target: FreezeBuilder> FreezeBuilder for StaticCompressor<Target> {
type Octets = Target::Octets;
fn freeze(self) -> Self::Octets {
self.target.freeze()
}
}
#[cfg(feature = "std")]
#[derive(Clone, Debug)]
pub struct TreeCompressor<Target> {
target: Target,
start: Node,
}
#[cfg(feature = "std")]
#[derive(Clone, Debug, Default)]
struct Node {
parents: HashMap<Array<64>, Self>,
value: Option<u16>,
}
#[cfg(feature = "std")]
impl Node {
fn drop_above(&mut self, len: u16) {
self.value = match self.value {
Some(value) if value < len => Some(value),
_ => None,
};
self.parents
.values_mut()
.for_each(|node| node.drop_above(len))
}
}
#[cfg(feature = "std")]
impl<Target> TreeCompressor<Target> {
pub fn new(target: Target) -> Self {
TreeCompressor {
target,
start: Default::default(),
}
}
pub fn as_target(&self) -> &Target {
&self.target
}
pub fn into_target(self) -> Target {
self.target
}
pub fn as_slice(&self) -> &[u8]
where
Target: AsRef<[u8]>,
{
self.target.as_ref()
}
pub fn as_slice_mut(&mut self) -> &mut [u8]
where
Target: AsMut<[u8]>,
{
self.target.as_mut()
}
fn get<'a, N: Iterator<Item = &'a Label> + Clone>(
&self,
name: N,
) -> Option<u16> {
let mut node = &self.start;
for label in name {
if label.is_root() {
return node.value;
}
node = node.parents.get(label.as_ref())?;
}
None
}
fn insert<'a, N: Iterator<Item = &'a Label> + Clone>(
&mut self,
name: N,
pos: usize,
) -> bool {
if pos >= 0xC000 {
return false;
}
let pos = pos as u16;
let mut node = &mut self.start;
for label in name {
if label.is_root() {
node.value = Some(pos);
break;
}
node = node
.parents
.entry(label.as_ref().try_into().unwrap())
.or_default();
}
true
}
}
#[cfg(feature = "std")]
impl<Target: AsRef<[u8]>> AsRef<[u8]> for TreeCompressor<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
#[cfg(feature = "std")]
impl<Target: AsMut<[u8]>> AsMut<[u8]> for TreeCompressor<Target> {
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
#[cfg(feature = "std")]
impl<Target: OctetsBuilder> OctetsBuilder for TreeCompressor<Target> {
type AppendError = Target::AppendError;
fn append_slice(
&mut self,
slice: &[u8],
) -> Result<(), Self::AppendError> {
self.target.append_slice(slice)
}
}
#[cfg(feature = "std")]
impl<Target: Composer> Composer for TreeCompressor<Target> {
fn append_compressed_name<N: ToName + ?Sized>(
&mut self,
name: &N,
) -> Result<(), Self::AppendError> {
let mut name = name.iter_labels().peekable();
loop {
if let Some(label) = name.peek() {
if label.is_root() {
label.compose(self)?;
return Ok(());
}
}
if let Some(pos) = self.get(name.clone()) {
return (pos | 0xC000).compose(self);
}
if !self.insert(name.clone(), self.target.as_ref().len()) {
for label in &mut name {
label.compose(self)?;
}
return Ok(());
}
let label = name.next().unwrap();
label.compose(self)?;
}
}
fn can_compress(&self) -> bool {
true
}
}
#[cfg(feature = "std")]
impl<Target: Composer> Truncate for TreeCompressor<Target> {
fn truncate(&mut self, len: usize) {
self.target.truncate(len);
if len < 0xC000 {
self.start.drop_above(len as u16)
}
}
}
#[cfg(feature = "std")]
impl<Target: FreezeBuilder> FreezeBuilder for TreeCompressor<Target> {
type Octets = Target::Octets;
fn freeze(self) -> Self::Octets {
self.target.freeze()
}
}
#[cfg(feature = "std")]
#[derive(Clone, Debug)]
pub struct HashCompressor<Target> {
target: Target,
names: HashTable<HashEntry>,
hasher: RandomState,
}
#[cfg(feature = "std")]
#[derive(Copy, Clone, Debug)]
struct HashEntry {
head: u16,
tail: u16,
}
#[cfg(feature = "std")]
impl HashEntry {
fn new(head: usize, tail: usize) -> Option<Self> {
if head < 0xC000 {
Some(Self {
head: head as u16,
tail: tail as u16,
})
} else {
None
}
}
fn head<'m>(&self, message: &'m [u8]) -> &'m Label {
Label::split_from(&message[self.head as usize..])
.expect("the message contains valid labels")
.0
}
fn hash(&self, message: &[u8], hasher: &RandomState) -> u64 {
hasher.hash_one((self.head(message), self.tail))
}
fn eq(&self, message: &[u8], query: (&Label, u16)) -> bool {
(self.head(message), self.tail) == query
}
}
#[cfg(feature = "std")]
impl<Target> HashCompressor<Target> {
pub fn new(target: Target) -> Self {
HashCompressor {
target,
names: Default::default(),
hasher: Default::default(),
}
}
pub fn as_target(&self) -> &Target {
&self.target
}
pub fn into_target(self) -> Target {
self.target
}
pub fn as_slice(&self) -> &[u8]
where
Target: AsRef<[u8]>,
{
self.target.as_ref()
}
pub fn as_slice_mut(&mut self) -> &mut [u8]
where
Target: AsMut<[u8]>,
{
self.target.as_mut()
}
}
#[cfg(feature = "std")]
impl<Target: AsRef<[u8]>> AsRef<[u8]> for HashCompressor<Target> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
#[cfg(feature = "std")]
impl<Target: AsMut<[u8]>> AsMut<[u8]> for HashCompressor<Target> {
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
#[cfg(feature = "std")]
impl<Target: OctetsBuilder> OctetsBuilder for HashCompressor<Target> {
type AppendError = Target::AppendError;
fn append_slice(
&mut self,
slice: &[u8],
) -> Result<(), Self::AppendError> {
self.target.append_slice(slice)
}
}
#[cfg(feature = "std")]
impl<Target: Composer> Composer for HashCompressor<Target> {
fn append_compressed_name<N: ToName + ?Sized>(
&mut self,
name: &N,
) -> Result<(), Self::AppendError> {
let mut name = name.iter_labels();
let message = self.target.as_ref();
assert!(
name.next_back().is_some_and(|l| l.is_root()),
"absolute names must end with a root label"
);
let mut position = 0xFFFF;
let mut last_label = None;
while let Some(label) = name.next_back() {
let query = (label, position);
let hash = self.hasher.hash_one(query);
let entry =
self.names.find(hash, |&name| name.eq(message, query));
if let Some(entry) = entry {
position = entry.head;
} else {
last_label = Some(label);
break;
}
}
let mut labels = name.chain(last_label).peekable();
while let Some(label) = labels.next() {
let head = self.target.as_ref().len();
let tail = head + label.compose_len() as usize;
label.compose(self)?;
if let Some(mut entry) = HashEntry::new(head, tail) {
if labels.peek().is_none() {
entry.tail = position;
}
let message = self.target.as_ref();
let hasher = &self.hasher;
let hash = entry.hash(message, hasher);
self.names.insert_unique(hash, entry, |&name| {
name.hash(message, hasher)
});
}
}
if position != 0xFFFF {
(position | 0xC000).compose(self)
} else {
Label::root().compose(self)
}
}
fn can_compress(&self) -> bool {
true
}
}
#[cfg(feature = "std")]
impl<Target: Composer> Truncate for HashCompressor<Target> {
fn truncate(&mut self, len: usize) {
self.target.truncate(len);
if len < 0xC000 {
self.names.retain(|name| name.head < len as u16);
}
}
}
#[cfg(feature = "std")]
impl<Target: FreezeBuilder> FreezeBuilder for HashCompressor<Target> {
type Octets = Target::Octets;
fn freeze(self) -> Self::Octets {
self.target.freeze()
}
}
#[derive(Clone, Copy, Debug)]
pub enum PushError {
CountOverflow,
LimitExceeded,
ShortBuf,
}
impl<T: Into<ShortBuf>> From<T> for PushError {
fn from(_: T) -> Self {
Self::ShortBuf
}
}
impl fmt::Display for PushError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
PushError::CountOverflow => f.write_str("counter overflow"),
PushError::LimitExceeded => f.write_str("limit exceeded"),
PushError::ShortBuf => ShortBuf.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PushError {}
#[cfg(test)]
#[cfg(feature = "std")]
mod test {
use super::*;
use crate::base::opt;
use crate::base::{Name, Serial, Ttl};
use crate::rdata::{Ns, Soa, A};
use core::str::FromStr;
#[test]
fn message_builder() {
let name = Name::<Vec<u8>>::from_str("example.com").unwrap();
let mut msg = MessageBuilder::from_target(StaticCompressor::new(
StreamTarget::new_vec(),
))
.unwrap();
msg.header_mut().set_rd(true);
let mut msg = msg.question();
msg.push((&name, Rtype::A)).unwrap();
let mut msg = msg.answer();
msg.push((&name, 86400, A::from_octets(192, 0, 2, 1)))
.unwrap();
msg.push((&name, 86400, A::from_octets(192, 0, 2, 2)))
.unwrap();
let mut msg = msg.authority();
msg.push((&name, 0, Ns::from(name.clone()))).unwrap();
let mut msg = msg.additional();
msg.push((&name, 86400, A::from_octets(192, 0, 2, 1)))
.unwrap();
let target = msg.finish().into_target();
let msg = Message::from_octets(target.as_dgram_slice()).unwrap();
let q = msg.first_question().unwrap();
assert_eq!(q.qname(), &name);
assert_eq!(q.qtype(), Rtype::A);
let section = msg.answer().unwrap();
let mut records = section.limit_to::<A>();
assert_eq!(
records.next().unwrap().unwrap().data(),
&A::from_octets(192, 0, 2, 1)
);
assert_eq!(
records.next().unwrap().unwrap().data(),
&A::from_octets(192, 0, 2, 2)
);
let section = msg.authority().unwrap();
let mut records = section.limit_to::<Ns<_>>();
let rr = records.next().unwrap().unwrap();
assert_eq!(rr.owner(), &name);
assert_eq!(rr.data().nsdname(), &name);
let section = msg.additional().unwrap();
let mut records = section.limit_to::<A>();
let rr = records.next().unwrap().unwrap();
assert_eq!(rr.owner(), &name);
assert_eq!(rr.data(), &A::from_octets(192, 0, 2, 1));
}
#[cfg(feature = "heapless")]
#[test]
fn exceed_limits() {
let buf = heapless::Vec::<u8, 100>::new();
let mut msg = MessageBuilder::from_target(buf).unwrap();
let hdr_len = msg.as_slice().len();
msg.push(|t| t.append_slice(&[0u8; 50]), |_| Ok(()))
.unwrap();
assert_eq!(msg.as_slice().len(), hdr_len + 50);
msg.set_push_limit(25);
assert!(matches!(
msg.push(|t| t.append_slice(&[0u8; 1]), |_| Ok(())),
Err(PushError::LimitExceeded)
));
assert_eq!(msg.as_slice().len(), hdr_len + 50);
msg.clear_push_limit();
for _ in (hdr_len + 50)..100 {
msg.push(|t| t.append_slice(&[0u8; 1]), |_| Ok(())).unwrap();
}
assert_eq!(msg.as_slice().len(), 100);
assert!(matches!(
msg.push(|t| t.append_slice(&[0u8; 1]), |_| Ok(())),
Err(PushError::ShortBuf)
));
assert_eq!(msg.as_slice().len(), 100);
}
#[test]
fn opt_builder() {
let mut msg = MessageBuilder::new_vec().additional();
let nsid = opt::nsid::Nsid::from_octets(&b"example"[..]).unwrap();
msg.opt(|o| {
o.set_udp_payload_size(4096);
o.push(&nsid)?;
Ok(())
})
.unwrap();
let msg = msg.finish();
println!("{:?}", msg);
let msg = Message::from_octets(msg).unwrap();
let opt = msg.opt().unwrap();
assert_eq!(opt.udp_payload_size(), 4096);
let mut opts = opt.opt().iter::<opt::nsid::Nsid<_>>();
assert_eq!(opts.next(), Some(Ok(nsid)));
}
fn create_compressed<T: Composer>(target: T) -> T
where
T::AppendError: fmt::Debug,
{
let mut msg = MessageBuilder::from_target(target).unwrap().question();
msg.header_mut().set_rcode(Rcode::NXDOMAIN);
msg.header_mut().set_rd(true);
msg.header_mut().set_ra(true);
msg.header_mut().set_qr(true);
msg.push((&"example".parse::<Name<Vec<u8>>>().unwrap(), Rtype::NS))
.unwrap();
let mut msg = msg.authority();
let mname: Name<Vec<u8>> = "a.root-servers.net".parse().unwrap();
let rname = "nstld.verisign-grs.com".parse().unwrap();
msg.push((
Name::root_slice(),
86390,
Soa::new(
mname,
rname,
Serial(2020081701),
Ttl::from_secs(1800),
Ttl::from_secs(900),
Ttl::from_secs(604800),
Ttl::from_secs(86400),
),
))
.unwrap();
msg.finish()
}
#[test]
fn compressor() {
let expect = &[
0x00, 0x00, 0x81, 0x83, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00, 0x00,
0x02, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01, 0x51,
0x76, 0x00, 0x40, 0x01, 0x61, 0x0c, 0x72, 0x6f, 0x6f, 0x74, 0x2d,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x03, 0x6e, 0x65, 0x74,
0x00, 0x05, 0x6e, 0x73, 0x74, 0x6c, 0x64, 0x0c, 0x76, 0x65, 0x72,
0x69, 0x73, 0x69, 0x67, 0x6e, 0x2d, 0x67, 0x72, 0x73, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0x78, 0x68, 0x00, 0x25, 0x00, 0x00, 0x07, 0x08,
0x00, 0x00, 0x03, 0x84, 0x00, 0x09, 0x3a, 0x80, 0x00, 0x01, 0x51,
0x80,
];
let msg = create_compressed(StaticCompressor::new(Vec::new()));
assert_eq!(&expect[..], msg.as_ref());
let msg = create_compressed(TreeCompressor::new(Vec::new()));
assert_eq!(&expect[..], msg.as_ref());
}
#[test]
fn compressor_into_message() {
let target = StaticCompressor::new(Vec::new());
let _msg =
MessageBuilder::from_target(target).unwrap().into_message();
let target = TreeCompressor::new(Vec::new());
let _msg =
MessageBuilder::from_target(target).unwrap().into_message();
let target = HashCompressor::new(Vec::new());
let _msg =
MessageBuilder::from_target(target).unwrap().into_message();
}
#[test]
fn compress_positive_response() {
let expect = &[
0x00, 0x00, 0x81, 0xa0, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x04, 0xcb, 0x00, 0x71,
0x01,
];
let name = "example.com.".parse::<Name<Vec<u8>>>().unwrap();
let mut msg =
MessageBuilder::from_target(StaticCompressor::new(Vec::new()))
.unwrap()
.question();
msg.header_mut().set_rcode(Rcode::NOERROR);
msg.header_mut().set_rd(true);
msg.header_mut().set_ra(true);
msg.header_mut().set_qr(true);
msg.header_mut().set_ad(true);
msg.push((name.clone(), Rtype::A)).unwrap();
let mut msg = msg.answer();
msg.push((name.clone(), 3600, A::from_octets(203, 0, 113, 1)))
.unwrap();
let actual = msg.finish().into_target();
assert_eq!(45, actual.len(), "unexpected response size");
assert_eq!(expect[..], actual, "unexpected response data");
}
#[cfg(feature = "std")]
#[test]
fn hash_compress_positive_response() {
let expect = &[
0x00, 0x00, 0x81, 0xa0, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x04, 0xcb, 0x00, 0x71,
0x01,
];
let name = "example.com.".parse::<Name<Vec<u8>>>().unwrap();
let mut msg =
MessageBuilder::from_target(HashCompressor::new(Vec::new()))
.unwrap()
.question();
msg.header_mut().set_rcode(Rcode::NOERROR);
msg.header_mut().set_rd(true);
msg.header_mut().set_ra(true);
msg.header_mut().set_qr(true);
msg.header_mut().set_ad(true);
msg.push((name.clone(), Rtype::A)).unwrap();
let mut msg = msg.answer();
msg.push((name.clone(), 3600, A::from_octets(203, 0, 113, 1)))
.unwrap();
let actual = msg.finish().into_target();
assert_eq!(45, actual.len(), "unexpected response size");
assert_eq!(expect[..], actual, "unexpected response data");
}
}