Skip to content

Commit 5b1b00e

Browse files
committed
rsscript: add gzip byte decompression
1 parent a7c0077 commit 5b1b00e

9 files changed

Lines changed: 136 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rsscript/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ toml = "0.8"
2121
serde_yaml_ng = "0.10"
2222
base64 = "0.22"
2323
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
24+
flate2 = "1"
2425
hex = "0.4"
2526
hmac = "0.12"
2627
percent-encoding = "2"

crates/rsscript/src/reg_vm/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::rc::Rc;
88

99
use base64::Engine;
1010
use chrono::{DateTime, Datelike, NaiveDate, SecondsFormat, TimeZone, Timelike, Utc};
11+
use flate2::read::GzDecoder;
1112
use hmac::{Hmac, Mac};
1213
use percent_encoding::{NON_ALPHANUMERIC, percent_decode_str, utf8_percent_encode};
1314
use rand::Rng;
@@ -2126,6 +2127,7 @@ enum RegIntrinsic {
21262127
HmacSha256String,
21272128
GlobalConfigNew,
21282129
GlobalConfigRuleCount,
2130+
GzipDecompressBytes,
21292131
HexDecode,
21302132
HexEncode,
21312133
HexEncodeString,
@@ -4227,6 +4229,7 @@ impl RegLowerer<'_> {
42274229
return Ok(dst);
42284230
}
42294231
("GlobalConfig", "rule_count") => RegIntrinsic::GlobalConfigRuleCount,
4232+
("Gzip", "decompress_bytes") => RegIntrinsic::GzipDecompressBytes,
42304233
("Hex", "decode") => RegIntrinsic::HexDecode,
42314234
("Hex", "encode") => RegIntrinsic::HexEncode,
42324235
("Hex", "encode_string") => RegIntrinsic::HexEncodeString,
@@ -9758,6 +9761,17 @@ impl RegVm {
97589761
let global = intrinsic_arg(&self.stack, base, args, 0)?;
97599762
Ok(VmValue::Int(expect_global_config_rule_count(global)?))
97609763
}
9764+
RegIntrinsic::GzipDecompressBytes => {
9765+
let value = expect_bytes_ref(intrinsic_arg(&self.stack, base, args, 0)?)?;
9766+
let mut decoder = GzDecoder::new(value);
9767+
let mut out = Vec::new();
9768+
Ok(json_result(
9769+
decoder
9770+
.read_to_end(&mut out)
9771+
.map(|_| VmValue::Bytes(Rc::new(out)))
9772+
.map_err(|error| decode_error_value(error.to_string())),
9773+
))
9774+
}
97619775
RegIntrinsic::HexDecode => {
97629776
let text = expect_string_ref(intrinsic_arg(&self.stack, base, args, 0)?)?;
97639777
Ok(json_result(

crates/rsscript/src/runtime_abi.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,11 @@ const RUNTIME_INTRINSICS: &[RuntimeIntrinsic] = &[
668668
"encode_string",
669669
"rsscript_runtime::hex_encode_string",
670670
),
671+
runtime_intrinsic(
672+
"Gzip",
673+
"decompress_bytes",
674+
"rsscript_runtime::gzip_decompress_bytes",
675+
),
671676
runtime_intrinsic("Http", "get", "rsscript_runtime::http_get"),
672677
runtime_intrinsic("Http", "get_async", "rsscript_runtime::http_get_async"),
673678
runtime_intrinsic("Http", "send_async", "rsscript_runtime::http_send_async"),

crates/rsscript/tests/vm.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,6 +1368,25 @@ fn main() -> Unit {
13681368
Err(error) => Log.write(message: read DecodeError.message(error: read error))
13691369
}
13701370
1371+
match Hex.decode(text: read "1f8b08000000000002ff4b4c4a0600c241243503000000") {
1372+
Ok(gzipped) => {
1373+
match Gzip.decompress_bytes(value: read gzipped) {
1374+
Ok(value) => {
1375+
Log.write(message: read String.from_int(value: Bytes.len(value: read value)))
1376+
Log.write(message: read Hex.encode(value: read value))
1377+
}
1378+
Err(error) => Log.write(message: read DecodeError.message(error: read error))
1379+
}
1380+
}
1381+
Err(error) => Log.write(message: read DecodeError.message(error: read error))
1382+
}
1383+
1384+
let bad_gzip = String.to_bytes(value: read "not gzip")
1385+
match Gzip.decompress_bytes(value: read bad_gzip) {
1386+
Ok(value) => Log.write(message: read String.from_int(value: Bytes.len(value: read value)))
1387+
Err(error) => Log.write(message: read DecodeError.message(error: read error))
1388+
}
1389+
13711390
let component = Url.encode_component(value: read "a b/é?x=1")
13721391
Log.write(message: read component)
13731392

crates/rsscript/tests/vm_eval_parity.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,25 @@ fn main() -> Unit {
10921092
Err(error) => Log.write(message: read DecodeError.message(error: read error))
10931093
}
10941094
1095+
match Hex.decode(text: read "1f8b08000000000002ff4b4c4a0600c241243503000000") {
1096+
Ok(gzipped) => {
1097+
match Gzip.decompress_bytes(value: read gzipped) {
1098+
Ok(value) => {
1099+
Log.write(message: read String.from_int(value: Bytes.len(value: read value)))
1100+
Log.write(message: read Hex.encode(value: read value))
1101+
}
1102+
Err(error) => Log.write(message: read DecodeError.message(error: read error))
1103+
}
1104+
}
1105+
Err(error) => Log.write(message: read DecodeError.message(error: read error))
1106+
}
1107+
1108+
let bad_gzip = String.to_bytes(value: read "not gzip")
1109+
match Gzip.decompress_bytes(value: read bad_gzip) {
1110+
Ok(value) => Log.write(message: read String.from_int(value: Bytes.len(value: read value)))
1111+
Err(error) => Log.write(message: read DecodeError.message(error: read error))
1112+
}
1113+
10951114
let component = Url.encode_component(value: read "a b/é?x=1")
10961115
Log.write(message: read component)
10971116

crates/runtime/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ sha3 = "0.10"
1919
regex = "1"
2020
base64 = "0.22"
2121
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
22+
flate2 = "1"
2223
hex = "0.4"
2324
hmac = "0.12"
2425
uuid = { version = "1", features = ["v4"] }

crates/runtime/src/encoding.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use base64::Engine;
22
use base64::engine::general_purpose::STANDARD;
3+
use flate2::read::GzDecoder;
34
use percent_encoding::{AsciiSet, NON_ALPHANUMERIC, percent_decode_str, utf8_percent_encode};
5+
use std::io::Read;
46

57
#[derive(Debug, Clone)]
68
pub struct DecodeError {
@@ -46,6 +48,17 @@ pub fn hex_decode(text: &str) -> Result<Vec<u8>, DecodeError> {
4648
})
4749
}
4850

51+
// Gzip
52+
53+
pub fn gzip_decompress_bytes(value: &[u8]) -> Result<Vec<u8>, DecodeError> {
54+
let mut decoder = GzDecoder::new(value);
55+
let mut out = Vec::new();
56+
decoder.read_to_end(&mut out).map_err(|e| DecodeError {
57+
message: e.to_string(),
58+
})?;
59+
Ok(out)
60+
}
61+
4962
// URL encoding
5063

5164
const COMPONENT_SET: &AsciiSet = &NON_ALPHANUMERIC
@@ -70,3 +83,21 @@ pub fn url_decode_component(value: &str) -> Result<String, DecodeError> {
7083
pub fn decode_error_message(error: &DecodeError) -> String {
7184
error.message.clone()
7285
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
91+
#[test]
92+
fn gzip_decompress_bytes_decodes_gzip_payload() {
93+
let gzipped = hex::decode("1f8b08000000000002ff4b4c4a0600c241243503000000").unwrap();
94+
let decoded = gzip_decompress_bytes(&gzipped).unwrap();
95+
assert_eq!(decoded, b"abc");
96+
}
97+
98+
#[test]
99+
fn gzip_decompress_bytes_reports_decode_errors() {
100+
let err = gzip_decompress_bytes(b"not gzip").unwrap_err();
101+
assert!(!err.message.is_empty());
102+
}
103+
}

stdlib/encoding/encoding.rssi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ pub native fn Hex.encode_string(value: read String) -> fresh String
2323
pub native fn Hex.decode(text: read String) -> Result<fresh Bytes, DecodeError>
2424
effects(native)
2525

26+
pub native fn Gzip.decompress_bytes(value: read Bytes) -> Result<fresh Bytes, DecodeError>
27+
effects(native)
28+
2629
pub native fn Url.encode_component(value: read String) -> fresh String
2730
effects(native)
2831

0 commit comments

Comments
 (0)