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