2019-07-01 15:43:34 +00:00
use crate ::errors ::* ;
use crate ::ser ::text ::{ DnsTextContext , quoted } ;
2017-12-21 12:32:14 +00:00
2018-02-10 10:32:25 +00:00
use super ::{ DnsName , DnsLabelRef } ;
2017-12-26 21:23:51 +00:00
2018-02-10 10:32:25 +00:00
/// Parse text representation of a domain name
pub fn parse_name ( context : & DnsTextContext , value : & str ) -> Result < DnsName >
{
let raw = value . as_bytes ( ) ;
let mut name = DnsName ::new_root ( ) ;
if raw = = b " . " {
return Ok ( name ) ;
} else if raw = = b " @ " {
match context . origin ( ) {
Some ( o ) = > return Ok ( o . clone ( ) ) ,
2019-07-01 15:43:34 +00:00
None = > failure ::bail! ( " @ invalid without $ORIGIN " ) ,
2018-02-10 10:32:25 +00:00
}
}
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! raw . is_empty ( ) , " invalid empty name " ) ;
2018-02-10 10:32:25 +00:00
let mut label = Vec ::new ( ) ;
let mut pos = 0 ;
while pos < raw . len ( ) {
if raw [ pos ] = = b '.' {
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! label . is_empty ( ) , " empty label in name: {:?} " , value ) ;
2017-12-21 12:32:14 +00:00
name . push_back ( DnsLabelRef ::new ( & label ) ? ) ? ;
2018-02-10 10:32:25 +00:00
label . clear ( ) ;
} else if raw [ pos ] = = b '\\' {
2019-07-01 15:43:34 +00:00
failure ::ensure! ( pos + 1 < raw . len ( ) , " unexpected end of name after backslash: {:?} " , value ) ;
2018-02-10 10:32:25 +00:00
if raw [ pos + 1 ] > = b '0' & & raw [ pos + 1 ] < = b '9' {
// \ddd escape
2019-07-01 15:43:34 +00:00
failure ::ensure! ( pos + 3 < raw . len ( ) , " unexpected end of name after backslash with digit: {:?} " , value ) ;
failure ::ensure! ( raw [ pos + 2 ] > = b '0' & & raw [ pos + 2 ] < = b '9' & & raw [ pos + 3 ] > = b '0' & & raw [ pos + 3 ] < = b '9' , " expected three digits after backslash in name: {:?} " , name ) ;
2018-02-10 10:32:25 +00:00
let d1 = ( raw [ pos + 1 ] - b '0' ) as u32 ;
let d2 = ( raw [ pos + 2 ] - b '0' ) as u32 ;
let d3 = ( raw [ pos + 3 ] - b '0' ) as u32 ;
let v = d1 * 100 + d2 * 10 + d3 ;
2019-07-01 15:43:34 +00:00
failure ::ensure! ( v < 256 , " invalid escape in name, {} > 255: {:?} " , v , name ) ;
2018-02-10 10:32:25 +00:00
label . push ( v as u8 ) ;
} else {
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! quoted ::is_ascii_whitespace ( raw [ pos + 1 ] ) , " whitespace cannot be escaped with backslash prefix; encode it as \\ {:03} in: {:?} " , raw [ pos + 1 ] , name ) ;
2018-02-10 10:32:25 +00:00
label . push ( raw [ pos + 1 ] ) ;
2017-12-26 21:23:51 +00:00
}
2018-02-10 10:32:25 +00:00
} else {
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! quoted ::is_ascii_whitespace ( raw [ pos ] ) , " whitespace must be encoded as \\ {:03} in: {:?} " , raw [ pos ] , name ) ;
2018-02-10 10:32:25 +00:00
label . push ( raw [ pos ] ) ;
2017-12-21 12:32:14 +00:00
}
2018-02-10 10:32:25 +00:00
pos + = 1 ;
2017-12-21 12:32:14 +00:00
}
2018-02-10 10:32:25 +00:00
if ! label . is_empty ( ) {
// no trailing dot, relative name
2017-12-21 12:32:14 +00:00
2018-02-10 10:32:25 +00:00
// push last label
name . push_back ( DnsLabelRef ::new ( & label ) ? ) ? ;
2017-12-21 12:32:14 +00:00
2018-02-10 10:32:25 +00:00
match context . origin ( ) {
Some ( o ) = > {
for l in o { name . push_back ( l ) ? ; }
} ,
2019-07-01 15:43:34 +00:00
None = > failure ::bail! ( " missing trailing dot without $ORIGIN " ) ,
2018-02-10 10:32:25 +00:00
}
2017-12-21 12:32:14 +00:00
}
2017-12-27 17:38:02 +00:00
2018-02-10 10:32:25 +00:00
Ok ( name )
2017-12-27 17:38:02 +00:00
}