haproxy_api/http_message.rs
1use std::ops::Deref;
2
3use mlua::{FromLua, Lua, ObjectLike, Result, String as LuaString, Table, Value};
4
5use crate::{Channel, Headers};
6
7/// This class contains all functions to manipulate an HTTP message.
8///
9/// For now, this class is only available from a filter context.
10#[derive(Clone)]
11pub struct HttpMessage(Table);
12
13impl HttpMessage {
14 /// Appends an HTTP header field in the HTTP message whose name is specified in `name`
15 /// and value is defined in `value`.
16 #[inline]
17 pub fn add_header(&self, name: &str, value: impl AsRef<[u8]>) -> Result<()> {
18 (self.0).call_method("add_header", (name, LuaString::wrap(value)))
19 }
20
21 /// Copies the string at the end of incoming data of the HTTP message.
22 ///
23 /// The function returns the copied length on success or -1 if data cannot be copied.
24 #[inline]
25 pub fn append(&self, data: impl AsRef<[u8]>) -> Result<isize> {
26 self.0.call_method("append", LuaString::wrap(data))
27 }
28
29 /// Returns `length` bytes of incoming data from the HTTP message, starting at the `offset`.
30 ///
31 /// The data are not removed from the buffer.
32 #[inline]
33 pub fn body(&self, offset: Option<isize>, length: Option<isize>) -> Result<Option<LuaString>> {
34 let offset = offset.unwrap_or(0);
35 match length {
36 Some(length) => self.0.call_method("body", (offset, length)),
37 None => self.0.call_method("body", offset),
38 }
39 }
40
41 /// Returns a corresponding channel attached to the HTTP message.
42 #[inline]
43 pub fn channel(&self) -> Result<Channel> {
44 self.0.raw_get("channel")
45 }
46
47 /// Returns true if the end of message is reached.
48 #[inline]
49 pub fn eom(&self) -> Result<bool> {
50 self.0.call_method("eom", ())
51 }
52
53 /// Removes all HTTP header fields in the HTTP message whose name is specified in name.
54 #[inline]
55 pub fn del_header(&self, name: &str) -> Result<()> {
56 self.0.call_method("del_header", name)
57 }
58
59 /// Returns a table containing all the headers of the HTTP message.
60 #[inline]
61 pub fn get_headers(&self) -> Result<Headers> {
62 self.0.call_method("get_headers", ())
63 }
64
65 /// Returns a table containing the start-line of the HTTP message.
66 #[inline]
67 pub fn get_stline(&self) -> Result<Table> {
68 self.0.call_method("get_stline", ())
69 }
70
71 /// Forwards `length` bytes of data from the HTTP message.
72 ///
73 /// Returns the amount of data forwarded.
74 ///
75 /// Because it is called in the filter context, it never yield.
76 /// Only available incoming data may be forwarded, event if the requested length exceeds the available amount of incoming data.
77 #[inline]
78 pub fn forward(&self, length: usize) -> Result<usize> {
79 self.0.call_method("forward", length)
80 }
81
82 /// Returns the length of incoming data in the HTTP message from the calling filter point of view.
83 #[inline]
84 pub fn input(&self) -> Result<usize> {
85 self.0.call_method("input", ())
86 }
87
88 /// Copies the `data` at the `offset` in incoming data of the HTTP message.
89 ///
90 /// Returns the copied length on success or -1 if data cannot be copied.
91 ///
92 /// By default, if no `offset` is provided, the string is copied in front of incoming data.
93 /// A positive `offset` is relative to the beginning of incoming data of the channel buffer while negative offset is relative to their end.
94 #[inline]
95 pub fn insert(&self, data: impl AsRef<[u8]>, offset: Option<isize>) -> Result<isize> {
96 let offset = offset.unwrap_or(0);
97 (self.0).call_method::<isize>("insert", (LuaString::wrap(data), offset))
98 }
99
100 /// Returns true if the HTTP message is full.
101 #[inline]
102 pub fn is_full(&self) -> Result<bool> {
103 self.0.call_method("is_full", ())
104 }
105
106 /// Returns true if the HTTP message is the response one.
107 #[inline]
108 pub fn is_resp(&self) -> Result<bool> {
109 self.0.call_method("is_resp", ())
110 }
111
112 /// Returns true if the HTTP message may still receive data.
113 #[inline]
114 pub fn may_recv(&self) -> Result<bool> {
115 self.0.call_method("may_recv", ())
116 }
117
118 /// Returns the length of outgoing data of the HTTP message.
119 #[inline]
120 pub fn output(&self) -> Result<usize> {
121 self.0.call_method("output", ())
122 }
123
124 /// Copies the `data` in front of incoming data of the HTTP message.
125 ///
126 /// Returns the copied length on success or -1 if data cannot be copied.
127 #[inline]
128 pub fn prepend(&self, data: impl AsRef<[u8]>) -> Result<isize> {
129 (self.0).call_method::<isize>("prepend", LuaString::wrap(data))
130 }
131
132 /// Removes `length` bytes of incoming data of the HTTP message, starting at `offset`.
133 ///
134 /// Returns number of bytes removed on success.
135 #[inline]
136 pub fn remove(&self, offset: Option<isize>, length: Option<usize>) -> Result<isize> {
137 let offset = offset.unwrap_or(0);
138 match length {
139 Some(length) => self.0.call_method("remove", (offset, length)),
140 None => self.0.call_method("remove", offset),
141 }
142 }
143
144 /// Matches the regular expression in all occurrences of header field `name` according to `regex`,
145 /// and replaces them with the `replace`.
146 ///
147 /// The replacement value can contain back references like 1, 2, ...
148 /// This function acts on whole header lines, regardless of the number of values they may contain.
149 #[inline]
150 pub fn rep_header(&self, name: &str, regex: &str, replace: &str) -> Result<()> {
151 self.0.call_method("rep_header", (name, regex, replace))
152 }
153
154 /// Matches the regular expression on every comma-delimited value of header field `name` according to `regex`,
155 /// and replaces them with the `replace`.
156 ///
157 /// The replacement value can contain back references like 1, 2, ...
158 #[inline]
159 pub fn rep_value(&self, name: &str, regex: &str, replace: &str) -> Result<()> {
160 self.0.call_method("rep_value", (name, regex, replace))
161 }
162
163 /// Requires immediate send of the `data`.
164 ///
165 /// It means the `data` is copied at the beginning of incoming data of the HTTP message and immediately forwarded.
166 ///
167 /// Because it is called in the filter context, it never yield.
168 #[inline]
169 pub fn send(&self, data: impl AsRef<[u8]>) -> Result<isize> {
170 self.0.call_method("send", LuaString::wrap(data))
171 }
172
173 /// Replaces `length` bytes of incoming data of the HTTP message, starting at `offset`, by the string `data`.
174 ///
175 /// Returns the copied length on success or -1 if data cannot be copied.
176 #[inline]
177 pub fn set(
178 &self,
179 data: impl AsRef<[u8]>,
180 offset: Option<isize>,
181 length: Option<usize>,
182 ) -> Result<isize> {
183 let data = LuaString::wrap(data);
184 let offset = offset.unwrap_or(0);
185 match length {
186 Some(length) => self.0.call_method("set", (data, offset, length)),
187 None => self.0.call_method("set", (data, offset)),
188 }
189 }
190
191 /// Changes the expected payload length of the HTTP message.
192 ///
193 /// Returns `true` if the payload length was successfully updated, `false` otherwise.
194 ///
195 /// If `length` is `None`, the HTTP message is forced to be chunk-encoded.
196 /// In that case, a `Transfer-Encoding` header is added with the “chunked” value.
197 ///
198 /// This function should be used in the filter context to be able to alter the payload of the HTTP message.
199 #[inline]
200 pub fn set_body_len(&self, length: Option<usize>) -> Result<bool> {
201 match length {
202 Some(length) => self.0.call_method("set_body_len", length),
203 None => self.0.call_method("set_body_len", "chunked"),
204 }
205 }
206
207 /// Sets or removes the flag that indicates end of message.
208 #[inline]
209 pub fn set_eom(&self, eom: bool) -> Result<()> {
210 match eom {
211 true => self.0.call_method("set_eom", ()),
212 false => self.0.call_method("unset_eom", ()),
213 }
214 }
215
216 /// Replaces all occurrence of all header matching the `name`, by only one containing the `value`.
217 #[inline]
218 pub fn set_header(&self, name: &str, value: impl AsRef<[u8]>) -> Result<()> {
219 (self.0).call_method("set_header", (name, LuaString::wrap(value)))
220 }
221
222 /// Rewrites the request method.
223 #[inline]
224 pub fn set_method(&self, method: &str) -> Result<()> {
225 self.0.call_method("set_method", method)
226 }
227
228 /// Rewrites the request path.
229 #[inline]
230 pub fn set_path(&self, path: &str) -> Result<()> {
231 self.0.call_method("set_path", path)
232 }
233
234 /// Rewrites the request’s query string which appears after the first question mark "?".
235 #[inline]
236 pub fn set_query(&self, query: &str) -> Result<()> {
237 self.0.call_method("set_query", query)
238 }
239
240 /// Rewrites the response status code with the new `status` and optional `reason`.
241 /// If no custom reason is provided, it will be generated from the status.
242 #[inline]
243 pub fn set_status(&self, status: u16, reason: Option<&str>) -> Result<()> {
244 self.0.call_method("set_status", (status, reason))
245 }
246
247 /// Rewrites the request URI.
248 #[inline]
249 pub fn set_uri(&self, uri: &str) -> Result<()> {
250 self.0.call_method("set_uri", uri)
251 }
252}
253
254impl FromLua for HttpMessage {
255 #[inline]
256 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
257 let class = Table::from_lua(value, lua)?;
258 Ok(HttpMessage(class))
259 }
260}
261
262impl Deref for HttpMessage {
263 type Target = Table;
264
265 #[inline]
266 fn deref(&self) -> &Self::Target {
267 &self.0
268 }
269}