fuchsia_url/
host.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::errors::ParseError;
6
7// The host of a fuchsia-pkg:// URL.
8#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub(crate) struct Host(String);
10
11impl Host {
12    /// Returns an error if the provided hostname does not comply to the package URL spec:
13    /// https://fuchsia.dev/fuchsia-src/concepts/packages/package_url#repository
14    /// Contains only lowercase ascii letters, digits, a hyphen or the dot delimiter.
15    pub fn parse(host: String) -> Result<Self, ParseError> {
16        url::Host::parse(&host)?;
17
18        if host.is_empty() {
19            return Err(ParseError::EmptyHost);
20        }
21
22        if !host
23            .chars()
24            .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-' || c == '.')
25        {
26            return Err(ParseError::InvalidHost);
27        }
28        Ok(Self(host))
29    }
30}
31
32impl AsRef<str> for Host {
33    fn as_ref(&self) -> &str {
34        &self.0
35    }
36}
37
38impl From<Host> for String {
39    fn from(host: Host) -> Self {
40        host.0
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn parse_err() {
50        for host in [
51            "FuChSiA.CoM",
52            "FUCHSIA_1.com",
53            "FUCHSIA-1.COM",
54            "fuchsia-①.com",
55            "RISCV.fuchsia.com",
56            "RV64.fuchsia.com",
57            "fu_chsia.com",
58        ] {
59            assert_eq!(
60                Host::parse(host.to_string()),
61                Err(ParseError::InvalidHost),
62                "the host string {:?}",
63                host
64            );
65        }
66
67        for host in ["fu:chsia.com", "fu#chsia.com", "fu?chsia.com", "fu/chsia.com"] {
68            assert_eq!(
69                Host::parse(host.to_string()),
70                Err(ParseError::UrlParseError(url::ParseError::InvalidDomainCharacter)),
71                "the host string {:?}",
72                host
73            );
74        }
75
76        assert_eq!(
77            Host::parse("".into()),
78            Err(ParseError::UrlParseError(url::ParseError::EmptyHost))
79        );
80    }
81
82    #[test]
83    fn parse_ok() {
84        for host in ["example.org", "ex.am.ple.org", "example0.org", "ex-ample.org", "a", "1", "."]
85        {
86            assert_eq!(Host::parse(host.to_string()).unwrap().as_ref(), host);
87        }
88    }
89}