blob: 116bcaeb8501672d32f7f13ac0bda6d4cee54269 [file] [log] [blame]
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! text records for storing arbitrary data
use std::slice::Iter;
use crate::error::*;
use crate::serialize::binary::*;
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
///
/// ```text
/// 3.3.14. TXT RDATA format
///
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// / TXT-DATA /
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///
///
/// TXT RRs are used to hold descriptive text. The semantics of the text
/// depends on the domain where it is found.
/// ```
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct TXT {
txt_data: Box<[Box<[u8]>]>,
}
impl TXT {
/// Creates a new TXT record data.
///
/// # Arguments
///
/// * `txt_data` - the set of strings which make up the txt_data.
///
/// # Return value
///
/// The new TXT record data.
pub fn new(txt_data: Vec<String>) -> TXT {
TXT {
txt_data: txt_data
.into_iter()
.map(|s| s.as_bytes().to_vec().into_boxed_slice())
.collect::<Vec<_>>()
.into_boxed_slice(),
}
}
/// ```text
/// TXT-DATA One or more <character-string>s.
/// ```
pub fn txt_data(&self) -> &[Box<[u8]>] {
&self.txt_data
}
/// Returns an iterator over the arrays in the txt data
pub fn iter(&self) -> Iter<Box<[u8]>> {
self.txt_data.iter()
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder, rdata_length: Restrict<u16>) -> ProtoResult<TXT> {
let data_len = decoder.len();
let mut strings = Vec::with_capacity(1);
// no unsafe usage of rdata length after this point
let rdata_length =
rdata_length.map(|u| u as usize).unverified(/*used as a higher bound, safely*/);
while data_len - decoder.len() < rdata_length {
let string =
decoder.read_character_data()?.unverified(/*any data should be validate in TXT usage*/);
strings.push(string.to_vec().into_boxed_slice());
}
Ok(TXT {
txt_data: strings.into_boxed_slice(),
})
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder, txt: &TXT) -> ProtoResult<()> {
for s in txt.txt_data() {
encoder.emit_character_data(s)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
#![allow(clippy::dbg_macro, clippy::print_stdout)]
use super::*;
#[test]
fn test() {
let rdata = TXT::new(vec!["Test me some".to_string(), "more please".to_string()]);
let mut bytes = Vec::new();
let mut encoder: BinEncoder = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {:?}", bytes);
let mut decoder: BinDecoder = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
}