Skip to main content

abuse_contact/
error.rs

1//! Error types for the crate.
2
3/// A value that cannot be used as a query or as a result.
4///
5/// These come from the constructors of the newtypes in this crate. A lookup that is
6/// certain to fail never reaches the network, and a placeholder a registry sends in
7/// place of a real address never reaches the caller.
8#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
9#[non_exhaustive]
10pub enum ValidationError {
11    /// The domain name was empty.
12    #[error("the domain name is empty. Give a name such as \"example.com\"")]
13    EmptyDomain,
14
15    /// The domain name was not shaped like a domain name.
16    #[error("\"{value}\" is not a domain name: {problem}")]
17    InvalidDomain {
18        /// The rejected value.
19        value: String,
20        /// What is wrong with it.
21        problem: &'static str,
22    },
23
24    /// The email address was not shaped like an email address.
25    #[error("\"{value}\" is not an email address: {problem}")]
26    InvalidEmail {
27        /// The rejected value.
28        value: String,
29        /// What is wrong with it.
30        problem: &'static str,
31    },
32
33    /// A source sent a fixed address that stands for "no contact published".
34    ///
35    /// A regional registry that withholds the contact of a network answers with one
36    /// address for every network in the region. The address is a marker, not a
37    /// mailbox that reads reports.
38    #[error(
39        "\"{value}\" is the address a source returns when it has no contact for the \
40         network, not a contact. Ask the regional registry, or use the technical \
41         contact from RDAP"
42    )]
43    WithheldEmail {
44        /// The marker the source sent.
45        value: String,
46    },
47
48    /// The registry sent a placeholder in place of an address.
49    ///
50    /// A registry that hides contact data puts a fixed string such as
51    /// `DATA REDACTED` in the field. The string is not an address and must not be
52    /// used as one.
53    #[error(
54        "\"{value}\" is a placeholder the registry sends in place of an address, \
55         not an address. Look for the abuse contact of the network instead"
56    )]
57    RedactedEmail {
58        /// The placeholder the registry sent.
59        value: String,
60    },
61}
62
63/// A lookup that did not finish.
64#[derive(Debug, thiserror::Error)]
65#[non_exhaustive]
66pub enum Error {
67    /// The request did not complete: DNS, TLS, connection or timeout.
68    #[error("the request to {server} did not complete: {source}")]
69    Transport {
70        /// The server the request went to.
71        server: String,
72        /// What the HTTP layer reported.
73        #[source]
74        source: Box<dyn std::error::Error + Send + Sync>,
75    },
76
77    /// The body was not the RDAP this crate expects.
78    #[error("{server} answered with a body that is not RDAP: {source}")]
79    Decode {
80        /// The server that answered.
81        server: String,
82        /// What the reader reported.
83        #[source]
84        source: serde_json::Error,
85    },
86
87    /// The server answered, and the answer was not a record.
88    #[error("{server} answered {status} for {target}")]
89    Status {
90        /// The server that answered.
91        server: String,
92        /// The HTTP status it sent.
93        status: u16,
94        /// What was asked about.
95        target: String,
96    },
97
98    /// The client did not send the request, or did not follow a redirect.
99    ///
100    /// A link in a record and a redirect from a server come from outside the process.
101    /// The client refuses one that goes to an address that is not public, uses a
102    /// scheme other than HTTP or HTTPS, drops from HTTPS to HTTP, or redirects too
103    /// many times.
104    #[error("the client did not request {server}: {reason}")]
105    Refused {
106        /// The URL the client did not request.
107        server: String,
108        /// Why.
109        reason: String,
110    },
111
112    /// The server sent a body longer than the crate reads.
113    ///
114    /// A record is a few kilobytes. A body past the limit is a fault on the server, or
115    /// a server that tries to use up the memory of the process.
116    #[error("{server} sent a body longer than {limit} bytes, which is more than a record")]
117    TooLarge {
118        /// The server that answered.
119        server: String,
120        /// The most the crate reads, in bytes.
121        limit: usize,
122    },
123
124    /// No registry holds the address or the name.
125    ///
126    /// The bootstrap registry names a server for every range IANA has given out. A
127    /// target with no server is a private address, a reserved range, or a name under
128    /// a top-level domain that runs no RDAP server.
129    #[error(
130        "no RDAP server answers for {target}. Check that it is a public address or a \
131         registered name, and not a private or reserved range"
132    )]
133    NoServer {
134        /// What was asked about.
135        target: String,
136    },
137
138    /// The address is not one the public registries describe.
139    ///
140    /// A regional registry holds a record for the reserved block a private address
141    /// sits in, and that record names IANA. Answering with it gives a contact that
142    /// cannot act, so the lookup stops here instead.
143    #[error(
144        "{target} is a private, reserved or documentation address. The registries \
145         describe the reserved block, not the host, so a report about it has no \
146         owner. Use the public address that carried the traffic"
147    )]
148    NotPublic {
149        /// The address that was asked about.
150        target: String,
151    },
152
153    /// A DNS lookup did not finish.
154    ///
155    /// A name that does not exist, or that holds no records of the type asked for, is
156    /// an answer and not this error. This is a lookup that got no answer: a timeout, a
157    /// server that failed, or a resolver configuration the system could not read.
158    #[error(
159        "the DNS lookup for {name} did not finish: {source}. Check that the system \
160         resolver answers, or give nameservers to Resolver::with_nameservers"
161    )]
162    Dns {
163        /// The name that was looked up, or what was being read.
164        name: String,
165        /// What the resolver reported.
166        #[source]
167        source: Box<dyn std::error::Error + Send + Sync>,
168    },
169
170    /// A value did not satisfy a documented limit.
171    #[error(transparent)]
172    Validation(#[from] ValidationError),
173}