Skip to main content

vrl/stdlib/
decode_gzip.rs

1use crate::compiler::prelude::*;
2use flate2::read::MultiGzDecoder;
3use std::io::Read;
4
5fn decode_gzip(value: Value) -> Resolved {
6    let value = value.try_bytes()?;
7    let mut buf = Vec::new();
8    let result = MultiGzDecoder::new(std::io::Cursor::new(value)).read_to_end(&mut buf);
9
10    match result {
11        Ok(_) => Ok(Value::Bytes(buf.into())),
12        Err(_) => Err("unable to decode value with Gzip decoder".into()),
13    }
14}
15
16#[derive(Clone, Copy, Debug)]
17pub struct DecodeGzip;
18
19impl Function for DecodeGzip {
20    fn identifier(&self) -> &'static str {
21        "decode_gzip"
22    }
23
24    fn usage(&self) -> &'static str {
25        "Decodes the `value` (a [Gzip](https://www.gzip.org/) string) into its original string."
26    }
27
28    fn category(&self) -> &'static str {
29        Category::Codec.as_ref()
30    }
31
32    fn internal_failure_reasons(&self) -> &'static [&'static str] {
33        &["`value` isn't a valid encoded Gzip string."]
34    }
35
36    fn return_kind(&self) -> u16 {
37        kind::BYTES
38    }
39
40    fn examples(&self) -> &'static [Example] {
41        &[example! {
42            title: "Decode Gzip data",
43            source: r#"decode_gzip!(decode_base64!("H4sIAB8BymMAAyvISU0sTlVISU3OT0lVyE0FAJsZ870QAAAA"))"#,
44            result: Ok("please decode me"),
45        }]
46    }
47
48    fn compile(
49        &self,
50        _state: &state::TypeState,
51        _ctx: &mut FunctionCompileContext,
52        arguments: ArgumentList,
53    ) -> Compiled {
54        let value = arguments.required("value");
55
56        Ok(DecodeGzipFn { value }.as_expr())
57    }
58
59    fn parameters(&self) -> &'static [Parameter] {
60        const PARAMETERS: &[Parameter] = &[Parameter::required(
61            "value",
62            kind::BYTES,
63            "The [Gzip](https://www.gzip.org/) data to decode.",
64        )];
65        PARAMETERS
66    }
67}
68
69#[derive(Clone, Debug)]
70struct DecodeGzipFn {
71    value: Box<dyn Expression>,
72}
73
74impl FunctionExpression for DecodeGzipFn {
75    fn resolve(&self, ctx: &mut Context) -> Resolved {
76        let value = self.value.resolve(ctx)?;
77
78        decode_gzip(value)
79    }
80
81    fn type_def(&self, _: &state::TypeState) -> TypeDef {
82        // Always fallible due to the possibility of decoding errors that VRL can't detect
83        TypeDef::bytes().fallible()
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::value;
91    use flate2::read::GzEncoder;
92    use nom::AsBytes;
93
94    fn get_encoded_bytes(text: &str) -> Vec<u8> {
95        let mut buf = Vec::new();
96        let mut gz = GzEncoder::new(text.as_bytes(), flate2::Compression::fast());
97        gz.read_to_end(&mut buf)
98            .expect("Cannot encode bytes with Gzip encoder");
99        buf
100    }
101
102    test_function![
103        decode_gzip => DecodeGzip;
104
105        right_gzip {
106            args: func_args![value: value!(get_encoded_bytes("sample").as_bytes())],
107            want: Ok(value!(b"sample")),
108            tdef: TypeDef::bytes().fallible(),
109        }
110
111        wrong_gzip {
112            args: func_args![value: value!("some_bytes")],
113            want: Err("unable to decode value with Gzip decoder"),
114            tdef: TypeDef::bytes().fallible(),
115        }
116    ];
117}