clamd_client/error.rs
1// for nicer doc links
2#[allow(unused_imports)]
3use crate::ClamdClient;
4use std::num::TryFromIntError;
5
6use tracing::trace;
7
8pub type Result<T> = std::result::Result<T, ClamdError>;
9
10/// Errors that can occur when using [`ClamdClient`].
11#[derive(Debug, thiserror::Error)]
12pub enum ClamdError {
13 /// Occurs when the custom set chunk size is larger than
14 /// [`std::u32::MAX`].
15 #[error("could not send chunk: too large: {0}")]
16 ChunkSizeError(#[source] TryFromIntError),
17 /// Occurs when the library cannot connect to the tcp or unix
18 /// socket. Contains underlying [`std::io::Error`].
19 #[error("could not connect to socket: {0}")]
20 ConnectError(#[source] std::io::Error),
21 /// Occurs when the clamd response is not valid Utf8.
22 #[error("could not decode clamav response: {0}")]
23 DecodingUtf8Error(#[source] std::string::FromUtf8Error),
24 /// Occurs when there was an [`std::io::Error`] while transfering
25 /// commands or data to/from clamd.
26 #[error("could not decode / encode clamav response: {0}")]
27 DecodingIoError(
28 #[from]
29 #[source]
30 std::io::Error,
31 ),
32
33 /// Occurs when the response from clamd is not what the library
34 /// expects. Contains the invalid response.
35 #[error("invalid response from clamd: {0}")]
36 InvalidResponse(String),
37 /// Occurs when there should be a response from clamd but it just
38 /// closed the connection without sending a response.
39 #[error("no response from clamd")]
40 NoResponse,
41 /// Occurs when we expect a longer response from clamd, but it
42 /// is somehow malformed. Contains the invalid response.
43 #[error("incomplete response from clamd: {0}")]
44 IncompleteResponse(String),
45 /// Occurs when everything between this library and clamd went
46 /// well but clamd seems to have found a virus signature. See also
47 /// [`ClamdError::scan_error`].
48 #[error("clamd returned error on scan, possible virus: {0}")]
49 ScanError(String),
50}
51
52impl ClamdError {
53 /// If you want to ignore any error but an actual malignent scan
54 /// result from clamd. I do not recommend using this without careful thought, as any other error
55 /// could hide that uploaded bytes are actually a virus.
56 /// # Example
57 /// ```rust
58 /// # use std::net::SocketAddr;
59 /// # use clamd_client::ClamdClientBuilder;
60 /// # use eyre::Result;
61 /// # async fn doc() -> eyre::Result<()> {
62 /// let address = "127.0.0.1:3310".parse::<SocketAddr>()?;
63 /// let mut clamd_client = ClamdClientBuilder::tcp_socket(&address).build();
64 ///
65 /// // This downloads a virus signature that is benign but trips clamd.
66 /// let eicar_bytes = reqwest::get("https://secure.eicar.org/eicarcom2.zip")
67 /// .await?
68 /// .bytes()
69 /// .await?;
70 ///
71 /// let err = clamd_client.scan_bytes(&eicar_bytes).await.unwrap_err();
72 /// let msg = err.scan_error().unwrap();
73 /// println!("Eicar scan returned that its a virus: {}", msg);
74 /// # Ok(())
75 /// # }
76 /// ```
77 pub fn scan_error(self) -> Option<String> {
78 match self {
79 Self::ScanError(s) => Some(s),
80 _ => {
81 trace!("ignoring non-scan error {:?}", self);
82 None
83 }
84 }
85 }
86}