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}