host.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. // Copyright 2013-2016 The rust-url developers.
  2. //
  3. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  5. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  6. // option. This file may not be copied, modified, or distributed
  7. // except according to those terms.
  8. use idna;
  9. use parser::{ParseError, ParseResult};
  10. use percent_encoding::{percent_decode, utf8_percent_encode, CONTROLS};
  11. use std::cmp;
  12. use std::fmt::{self, Formatter};
  13. use std::net::{Ipv4Addr, Ipv6Addr};
  14. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  15. pub enum HostInternal {
  16. None,
  17. Domain,
  18. Ipv4(Ipv4Addr),
  19. Ipv6(Ipv6Addr),
  20. }
  21. #[cfg(feature = "serde")]
  22. impl ::serde::Serialize for HostInternal {
  23. fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  24. where
  25. S: ::serde::Serializer,
  26. {
  27. // This doesn’t use `derive` because that involves
  28. // large dependencies (that take a long time to build), and
  29. // either Macros 1.1 which are not stable yet or a cumbersome build script.
  30. //
  31. // Implementing `Serializer` correctly for an enum is tricky,
  32. // so let’s use existing enums that already do.
  33. use std::net::IpAddr;
  34. match *self {
  35. HostInternal::None => None,
  36. HostInternal::Domain => Some(None),
  37. HostInternal::Ipv4(addr) => Some(Some(IpAddr::V4(addr))),
  38. HostInternal::Ipv6(addr) => Some(Some(IpAddr::V6(addr))),
  39. }
  40. .serialize(serializer)
  41. }
  42. }
  43. #[cfg(feature = "serde")]
  44. impl<'de> ::serde::Deserialize<'de> for HostInternal {
  45. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  46. where
  47. D: ::serde::Deserializer<'de>,
  48. {
  49. use std::net::IpAddr;
  50. Ok(match ::serde::Deserialize::deserialize(deserializer)? {
  51. None => HostInternal::None,
  52. Some(None) => HostInternal::Domain,
  53. Some(Some(IpAddr::V4(addr))) => HostInternal::Ipv4(addr),
  54. Some(Some(IpAddr::V6(addr))) => HostInternal::Ipv6(addr),
  55. })
  56. }
  57. }
  58. impl<S> From<Host<S>> for HostInternal {
  59. fn from(host: Host<S>) -> HostInternal {
  60. match host {
  61. Host::Domain(_) => HostInternal::Domain,
  62. Host::Ipv4(address) => HostInternal::Ipv4(address),
  63. Host::Ipv6(address) => HostInternal::Ipv6(address),
  64. }
  65. }
  66. }
  67. /// The host name of an URL.
  68. #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
  69. pub enum Host<S = String> {
  70. /// A DNS domain name, as '.' dot-separated labels.
  71. /// Non-ASCII labels are encoded in punycode per IDNA if this is the host of
  72. /// a special URL, or percent encoded for non-special URLs. Hosts for
  73. /// non-special URLs are also called opaque hosts.
  74. Domain(S),
  75. /// An IPv4 address.
  76. /// `Url::host_str` returns the serialization of this address,
  77. /// as four decimal integers separated by `.` dots.
  78. Ipv4(Ipv4Addr),
  79. /// An IPv6 address.
  80. /// `Url::host_str` returns the serialization of that address between `[` and `]` brackets,
  81. /// in the format per [RFC 5952 *A Recommendation
  82. /// for IPv6 Address Text Representation*](https://tools.ietf.org/html/rfc5952):
  83. /// lowercase hexadecimal with maximal `::` compression.
  84. Ipv6(Ipv6Addr),
  85. }
  86. #[cfg(feature = "serde")]
  87. impl<S: ::serde::Serialize> ::serde::Serialize for Host<S> {
  88. fn serialize<R>(&self, serializer: R) -> Result<R::Ok, R::Error>
  89. where
  90. R: ::serde::Serializer,
  91. {
  92. use std::net::IpAddr;
  93. match *self {
  94. Host::Domain(ref s) => Ok(s),
  95. Host::Ipv4(addr) => Err(IpAddr::V4(addr)),
  96. Host::Ipv6(addr) => Err(IpAddr::V6(addr)),
  97. }
  98. .serialize(serializer)
  99. }
  100. }
  101. #[cfg(feature = "serde")]
  102. impl<'de, S: ::serde::Deserialize<'de>> ::serde::Deserialize<'de> for Host<S> {
  103. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  104. where
  105. D: ::serde::Deserializer<'de>,
  106. {
  107. use std::net::IpAddr;
  108. Ok(match ::serde::Deserialize::deserialize(deserializer)? {
  109. Ok(s) => Host::Domain(s),
  110. Err(IpAddr::V4(addr)) => Host::Ipv4(addr),
  111. Err(IpAddr::V6(addr)) => Host::Ipv6(addr),
  112. })
  113. }
  114. }
  115. impl<'a> Host<&'a str> {
  116. /// Return a copy of `self` that owns an allocated `String` but does not borrow an `&Url`.
  117. pub fn to_owned(&self) -> Host<String> {
  118. match *self {
  119. Host::Domain(domain) => Host::Domain(domain.to_owned()),
  120. Host::Ipv4(address) => Host::Ipv4(address),
  121. Host::Ipv6(address) => Host::Ipv6(address),
  122. }
  123. }
  124. }
  125. impl Host<String> {
  126. /// Parse a host: either an IPv6 address in [] square brackets, or a domain.
  127. ///
  128. /// <https://url.spec.whatwg.org/#host-parsing>
  129. pub fn parse(input: &str) -> Result<Self, ParseError> {
  130. if input.starts_with('[') {
  131. if !input.ends_with(']') {
  132. return Err(ParseError::InvalidIpv6Address);
  133. }
  134. return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6);
  135. }
  136. let domain = percent_decode(input.as_bytes()).decode_utf8_lossy();
  137. let domain = idna::domain_to_ascii(&domain)?;
  138. if domain
  139. .find(|c| {
  140. matches!(
  141. c,
  142. '\0' | '\t'
  143. | '\n'
  144. | '\r'
  145. | ' '
  146. | '#'
  147. | '%'
  148. | '/'
  149. | ':'
  150. | '?'
  151. | '@'
  152. | '['
  153. | '\\'
  154. | ']'
  155. )
  156. })
  157. .is_some()
  158. {
  159. return Err(ParseError::InvalidDomainCharacter);
  160. }
  161. if let Some(address) = parse_ipv4addr(&domain)? {
  162. Ok(Host::Ipv4(address))
  163. } else {
  164. Ok(Host::Domain(domain.into()))
  165. }
  166. }
  167. // <https://url.spec.whatwg.org/#concept-opaque-host-parser>
  168. pub fn parse_opaque(input: &str) -> Result<Self, ParseError> {
  169. if input.starts_with('[') {
  170. if !input.ends_with(']') {
  171. return Err(ParseError::InvalidIpv6Address);
  172. }
  173. return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6);
  174. }
  175. if input
  176. .find(|c| {
  177. matches!(
  178. c,
  179. '\0' | '\t'
  180. | '\n'
  181. | '\r'
  182. | ' '
  183. | '#'
  184. | '/'
  185. | ':'
  186. | '?'
  187. | '@'
  188. | '['
  189. | '\\'
  190. | ']'
  191. )
  192. })
  193. .is_some()
  194. {
  195. return Err(ParseError::InvalidDomainCharacter);
  196. }
  197. let s = utf8_percent_encode(input, CONTROLS).to_string();
  198. Ok(Host::Domain(s))
  199. }
  200. }
  201. impl<S: AsRef<str>> fmt::Display for Host<S> {
  202. fn fmt(&self, f: &mut Formatter) -> fmt::Result {
  203. match *self {
  204. Host::Domain(ref domain) => domain.as_ref().fmt(f),
  205. Host::Ipv4(ref addr) => addr.fmt(f),
  206. Host::Ipv6(ref addr) => {
  207. f.write_str("[")?;
  208. write_ipv6(addr, f)?;
  209. f.write_str("]")
  210. }
  211. }
  212. }
  213. }
  214. fn write_ipv6(addr: &Ipv6Addr, f: &mut Formatter) -> fmt::Result {
  215. let segments = addr.segments();
  216. let (compress_start, compress_end) = longest_zero_sequence(&segments);
  217. let mut i = 0;
  218. while i < 8 {
  219. if i == compress_start {
  220. f.write_str(":")?;
  221. if i == 0 {
  222. f.write_str(":")?;
  223. }
  224. if compress_end < 8 {
  225. i = compress_end;
  226. } else {
  227. break;
  228. }
  229. }
  230. write!(f, "{:x}", segments[i as usize])?;
  231. if i < 7 {
  232. f.write_str(":")?;
  233. }
  234. i += 1;
  235. }
  236. Ok(())
  237. }
  238. // https://url.spec.whatwg.org/#concept-ipv6-serializer step 2 and 3
  239. fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) {
  240. let mut longest = -1;
  241. let mut longest_length = -1;
  242. let mut start = -1;
  243. macro_rules! finish_sequence(
  244. ($end: expr) => {
  245. if start >= 0 {
  246. let length = $end - start;
  247. if length > longest_length {
  248. longest = start;
  249. longest_length = length;
  250. }
  251. }
  252. };
  253. );
  254. for i in 0..8 {
  255. if pieces[i as usize] == 0 {
  256. if start < 0 {
  257. start = i;
  258. }
  259. } else {
  260. finish_sequence!(i);
  261. start = -1;
  262. }
  263. }
  264. finish_sequence!(8);
  265. // https://url.spec.whatwg.org/#concept-ipv6-serializer
  266. // step 3: ignore lone zeroes
  267. if longest_length < 2 {
  268. (-1, -2)
  269. } else {
  270. (longest, longest + longest_length)
  271. }
  272. }
  273. /// <https://url.spec.whatwg.org/#ipv4-number-parser>
  274. fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
  275. let mut r = 10;
  276. if input.starts_with("0x") || input.starts_with("0X") {
  277. input = &input[2..];
  278. r = 16;
  279. } else if input.len() >= 2 && input.starts_with('0') {
  280. input = &input[1..];
  281. r = 8;
  282. }
  283. // At the moment we can't know the reason why from_str_radix fails
  284. // https://github.com/rust-lang/rust/issues/22639
  285. // So instead we check if the input looks like a real number and only return
  286. // an error when it's an overflow.
  287. let valid_number = match r {
  288. 8 => input.chars().all(|c| c >= '0' && c <= '7'),
  289. 10 => input.chars().all(|c| c >= '0' && c <= '9'),
  290. 16 => input
  291. .chars()
  292. .all(|c| (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')),
  293. _ => false,
  294. };
  295. if !valid_number {
  296. return Ok(None);
  297. }
  298. if input.is_empty() {
  299. return Ok(Some(0));
  300. }
  301. if input.starts_with('+') {
  302. return Ok(None);
  303. }
  304. match u32::from_str_radix(input, r) {
  305. Ok(number) => Ok(Some(number)),
  306. Err(_) => Err(()),
  307. }
  308. }
  309. /// <https://url.spec.whatwg.org/#concept-ipv4-parser>
  310. fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
  311. if input.is_empty() {
  312. return Ok(None);
  313. }
  314. let mut parts: Vec<&str> = input.split('.').collect();
  315. if parts.last() == Some(&"") {
  316. parts.pop();
  317. }
  318. if parts.len() > 4 {
  319. return Ok(None);
  320. }
  321. let mut numbers: Vec<u32> = Vec::new();
  322. let mut overflow = false;
  323. for part in parts {
  324. if part == "" {
  325. return Ok(None);
  326. }
  327. match parse_ipv4number(part) {
  328. Ok(Some(n)) => numbers.push(n),
  329. Ok(None) => return Ok(None),
  330. Err(()) => overflow = true,
  331. };
  332. }
  333. if overflow {
  334. return Err(ParseError::InvalidIpv4Address);
  335. }
  336. let mut ipv4 = numbers.pop().expect("a non-empty list of numbers");
  337. // Equivalent to: ipv4 >= 256 ** (4 − numbers.len())
  338. if ipv4 > u32::max_value() >> (8 * numbers.len() as u32) {
  339. return Err(ParseError::InvalidIpv4Address);
  340. }
  341. if numbers.iter().any(|x| *x > 255) {
  342. return Err(ParseError::InvalidIpv4Address);
  343. }
  344. for (counter, n) in numbers.iter().enumerate() {
  345. ipv4 += n << (8 * (3 - counter as u32))
  346. }
  347. Ok(Some(Ipv4Addr::from(ipv4)))
  348. }
  349. /// <https://url.spec.whatwg.org/#concept-ipv6-parser>
  350. fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> {
  351. let input = input.as_bytes();
  352. let len = input.len();
  353. let mut is_ip_v4 = false;
  354. let mut pieces = [0, 0, 0, 0, 0, 0, 0, 0];
  355. let mut piece_pointer = 0;
  356. let mut compress_pointer = None;
  357. let mut i = 0;
  358. if len < 2 {
  359. return Err(ParseError::InvalidIpv6Address);
  360. }
  361. if input[0] == b':' {
  362. if input[1] != b':' {
  363. return Err(ParseError::InvalidIpv6Address);
  364. }
  365. i = 2;
  366. piece_pointer = 1;
  367. compress_pointer = Some(1);
  368. }
  369. while i < len {
  370. if piece_pointer == 8 {
  371. return Err(ParseError::InvalidIpv6Address);
  372. }
  373. if input[i] == b':' {
  374. if compress_pointer.is_some() {
  375. return Err(ParseError::InvalidIpv6Address);
  376. }
  377. i += 1;
  378. piece_pointer += 1;
  379. compress_pointer = Some(piece_pointer);
  380. continue;
  381. }
  382. let start = i;
  383. let end = cmp::min(len, start + 4);
  384. let mut value = 0u16;
  385. while i < end {
  386. match (input[i] as char).to_digit(16) {
  387. Some(digit) => {
  388. value = value * 0x10 + digit as u16;
  389. i += 1;
  390. }
  391. None => break,
  392. }
  393. }
  394. if i < len {
  395. match input[i] {
  396. b'.' => {
  397. if i == start {
  398. return Err(ParseError::InvalidIpv6Address);
  399. }
  400. i = start;
  401. if piece_pointer > 6 {
  402. return Err(ParseError::InvalidIpv6Address);
  403. }
  404. is_ip_v4 = true;
  405. }
  406. b':' => {
  407. i += 1;
  408. if i == len {
  409. return Err(ParseError::InvalidIpv6Address);
  410. }
  411. }
  412. _ => return Err(ParseError::InvalidIpv6Address),
  413. }
  414. }
  415. if is_ip_v4 {
  416. break;
  417. }
  418. pieces[piece_pointer] = value;
  419. piece_pointer += 1;
  420. }
  421. if is_ip_v4 {
  422. if piece_pointer > 6 {
  423. return Err(ParseError::InvalidIpv6Address);
  424. }
  425. let mut numbers_seen = 0;
  426. while i < len {
  427. if numbers_seen > 0 {
  428. if numbers_seen < 4 && (i < len && input[i] == b'.') {
  429. i += 1
  430. } else {
  431. return Err(ParseError::InvalidIpv6Address);
  432. }
  433. }
  434. let mut ipv4_piece = None;
  435. while i < len {
  436. let digit = match input[i] {
  437. c @ b'0'..=b'9' => c - b'0',
  438. _ => break,
  439. };
  440. match ipv4_piece {
  441. None => ipv4_piece = Some(digit as u16),
  442. Some(0) => return Err(ParseError::InvalidIpv6Address), // No leading zero
  443. Some(ref mut v) => {
  444. *v = *v * 10 + digit as u16;
  445. if *v > 255 {
  446. return Err(ParseError::InvalidIpv6Address);
  447. }
  448. }
  449. }
  450. i += 1;
  451. }
  452. pieces[piece_pointer] = if let Some(v) = ipv4_piece {
  453. pieces[piece_pointer] * 0x100 + v
  454. } else {
  455. return Err(ParseError::InvalidIpv6Address);
  456. };
  457. numbers_seen += 1;
  458. if numbers_seen == 2 || numbers_seen == 4 {
  459. piece_pointer += 1;
  460. }
  461. }
  462. if numbers_seen != 4 {
  463. return Err(ParseError::InvalidIpv6Address);
  464. }
  465. }
  466. if i < len {
  467. return Err(ParseError::InvalidIpv6Address);
  468. }
  469. match compress_pointer {
  470. Some(compress_pointer) => {
  471. let mut swaps = piece_pointer - compress_pointer;
  472. piece_pointer = 7;
  473. while swaps > 0 {
  474. pieces.swap(piece_pointer, compress_pointer + swaps - 1);
  475. swaps -= 1;
  476. piece_pointer -= 1;
  477. }
  478. }
  479. _ => {
  480. if piece_pointer != 8 {
  481. return Err(ParseError::InvalidIpv6Address);
  482. }
  483. }
  484. }
  485. Ok(Ipv6Addr::new(
  486. pieces[0], pieces[1], pieces[2], pieces[3], pieces[4], pieces[5], pieces[6], pieces[7],
  487. ))
  488. }