1use std::path::PathBuf;
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Debug, Error)]
11pub enum Error {
12 #[error("parse error at {location}: {message}")]
14 Parse {
15 message: String,
17 location: String,
19 source_text: Option<String>,
21 },
22
23 #[error("failed to load rule file {path}: {source}")]
25 RuleFileLoad {
26 path: PathBuf,
28 #[source]
30 source: std::io::Error,
31 },
32
33 #[error("invalid regex pattern '{pattern}': {source}")]
35 RegexCompile {
36 pattern: String,
38 #[source]
40 source: regex::Error,
41 },
42
43 #[error("invalid pattern set: {message}")]
45 PatternSet {
46 message: String,
48 },
49
50 #[error("invalid IP address or network '{value}': {message}")]
52 InvalidIp {
53 value: String,
55 message: String,
57 },
58
59 #[error("unknown variable: {name}")]
61 UnknownVariable {
62 name: String,
64 },
65
66 #[error("unknown operator: @{name}")]
68 UnknownOperator {
69 name: String,
71 },
72
73 #[error("unknown transformation: t:{name}")]
75 UnknownTransformation {
76 name: String,
78 },
79
80 #[error("unknown action: {name}")]
82 UnknownAction {
83 name: String,
85 },
86
87 #[error("invalid argument for action '{action}': {message}")]
89 InvalidActionArgument {
90 action: String,
92 message: String,
94 },
95
96 #[error("rule is missing required 'id' action")]
98 MissingRuleId,
99
100 #[error("duplicate rule id: {id}")]
102 DuplicateRuleId {
103 id: u64,
105 },
106
107 #[error("incomplete rule chain: chain action without following rule")]
109 IncompleteChain,
110
111 #[error("failed to process URI: {message}")]
113 ProcessUri {
114 message: String,
116 },
117
118 #[error("failed to process request headers: {message}")]
120 ProcessRequestHeaders {
121 message: String,
123 },
124
125 #[error("failed to process request body: {message}")]
127 ProcessRequestBody {
128 message: String,
130 },
131
132 #[error("failed to process response headers: {message}")]
134 ProcessResponseHeaders {
135 message: String,
137 },
138
139 #[error("failed to process response body: {message}")]
141 ProcessResponseBody {
142 message: String,
144 },
145
146 #[error("configuration error: {message}")]
148 Config {
149 message: String,
151 },
152
153 #[error("internal error: {message}")]
155 Internal {
156 message: String,
158 },
159}
160
161impl Error {
162 pub fn parse(message: impl Into<String>, location: impl Into<String>) -> Self {
164 Self::Parse {
165 message: message.into(),
166 location: location.into(),
167 source_text: None,
168 }
169 }
170
171 pub fn parse_with_source(
173 message: impl Into<String>,
174 location: impl Into<String>,
175 source_text: impl Into<String>,
176 ) -> Self {
177 Self::Parse {
178 message: message.into(),
179 location: location.into(),
180 source_text: Some(source_text.into()),
181 }
182 }
183}
184
185#[derive(Debug, Clone, Default)]
187pub struct SourceLocation {
188 pub file: Option<PathBuf>,
190 pub line: usize,
192 pub column: usize,
194}
195
196impl std::fmt::Display for SourceLocation {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 if let Some(ref file) = self.file {
199 write!(f, "{}:{}:{}", file.display(), self.line, self.column)
200 } else {
201 write!(f, "{}:{}", self.line, self.column)
202 }
203 }
204}