Skip to content

Commit

Permalink
Merge pull request matrix-org#3 from SpectralOps/implement-urlquery-b…
Browse files Browse the repository at this point in the history
…uiltins

implement urlquery
  • Loading branch information
jondot authored Nov 11, 2022
2 parents a62788a + b7fa3a4 commit f3e148b
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 12 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ globset = { version = "0.4.9", optional = true }
regex = { version = "1.7.0", optional = true }
route-pattern = { version = "0.1.0", optional = true }
regex-intersect = { version = "1.2.0", optional = true }
form_urlencoded = { version = "1.1.0", optional = true }
urlencoding = { version = "2.1.2", optional = true }

[dev-dependencies.tokio]
version = "1.5"
Expand Down Expand Up @@ -108,6 +110,7 @@ rand-builtins = ["rng"]
yaml-builtins = ["dep:serde_yaml"]
glob-builtins = ["dep:globset"]
regex-builtins = ["dep:regex", "dep:route-pattern", "dep:regex-intersect"]
urlquery-builtins = ["dep:form_urlencoded", "dep:urlencoding"]

all-crypto-builtins = [
"crypto-digest-builtins",
Expand All @@ -129,6 +132,7 @@ all-builtins = [
"yaml-builtins",
"glob-builtins",
"regex-builtins",
"urlquery-builtins",
]

[[test]]
Expand Down
1 change: 1 addition & 0 deletions src/builtins/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub mod semver;
pub mod time;
#[cfg(feature = "units-builtins")]
pub mod units;
#[cfg(feature = "urlquery-builtins")]
pub mod urlquery;
pub mod uuid;
#[cfg(feature = "yaml-builtins")]
Expand Down
45 changes: 34 additions & 11 deletions src/builtins/impls/urlquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,51 @@
use std::collections::HashMap;

use anyhow::{bail, Result};
use anyhow::Result;
use serde_json::Value;

/// Decodes a URL-encoded input string.
#[tracing::instrument(name = "urlquery.decode", err)]
pub fn decode(x: String) -> Result<String> {
bail!("not implemented");
Ok(urlencoding::decode(&x)?.into_owned())
}

/// Decodes the given URL query string into an object.
#[tracing::instrument(name = "urlquery.decode_object", err)]
pub fn decode_object(x: String) -> Result<HashMap<String, Vec<String>>> {
bail!("not implemented");
#[tracing::instrument(name = "urlquery.decode_object")]
pub fn decode_object(x: String) -> HashMap<String, Vec<String>> {
let parsed = form_urlencoded::parse(x.as_bytes()).into_owned();
let mut decoded_object: HashMap<String, Vec<String>> = HashMap::new();
for (k, v) in parsed {
decoded_object.entry(k).or_default().push(v);
}
decoded_object
}

/// Encodes the input string into a URL-encoded string.
#[tracing::instrument(name = "urlquery.encode", err)]
pub fn encode(x: String) -> Result<String> {
bail!("not implemented");
#[tracing::instrument(name = "urlquery.encode")]
pub fn encode(x: String) -> String {
form_urlencoded::byte_serialize(x.as_bytes()).collect()
}

/// Encodes the given object into a URL encoded query string.
#[tracing::instrument(name = "urlquery.encode_object", err)]
pub fn encode_object(x: HashMap<String, serde_json::Value>) -> Result<String> {
bail!("not implemented");
#[tracing::instrument(name = "urlquery.encode_object")]
pub fn encode_object(x: HashMap<String, serde_json::Value>) -> String {
let mut encoded = form_urlencoded::Serializer::new(String::new());

let mut sorted: Vec<_> = x.iter().collect();
sorted.sort_by_key(|a| a.0);

sorted
.iter()
.for_each(|(parameter_key, parameter_value)| match &parameter_value {
Value::Array(arr) => {
for v in arr.iter() {
encoded.append_pair(parameter_key, v.as_str().unwrap_or_default());
}
}
_ => {
encoded.append_pair(parameter_key, parameter_value.as_str().unwrap_or_default());
}
});
encoded.finish()
}
5 changes: 5 additions & 0 deletions src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,15 @@ pub fn resolve<C: EvaluationContext>(name: &str) -> Result<Box<dyn Builtin<C>>>
#[cfg(feature = "units-builtins")]
"units.parse_bytes" => Ok(self::impls::units::parse_bytes.wrap()),

#[cfg(feature = "urlquery-builtins")]
"urlquery.decode" => Ok(self::impls::urlquery::decode.wrap()),
#[cfg(feature = "urlquery-builtins")]
"urlquery.decode_object" => Ok(self::impls::urlquery::decode_object.wrap()),
#[cfg(feature = "urlquery-builtins")]
"urlquery.encode" => Ok(self::impls::urlquery::encode.wrap()),
#[cfg(feature = "urlquery-builtins")]
"urlquery.encode_object" => Ok(self::impls::urlquery::encode_object.wrap()),

"uuid.rfc4122" => Ok(self::impls::uuid::rfc4122.wrap()),

#[cfg(feature = "yaml-builtins")]
Expand Down
19 changes: 19 additions & 0 deletions tests/infra-fixtures/test-urlquery.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package test

encode_none := urlquery.encode("")

encode_normaltext := urlquery.encode("abc")

encode_1 := urlquery.encode("?foo=1&bar=test")

encode_2 := urlquery.decode("&&&&")

encode_3 := urlquery.decode("====")

encode_4 := urlquery.decode("&=&=")

encode_object := urlquery.encode_object({"foo": "1", "bar": "foo&foo", "arr": ["foo", "bar"], "obj": {"obj1", "obj2"}})

decode := urlquery.decode("%3Ffoo%3D1%26bar%3Dtest")

decode_object := urlquery.decode_object("arr=foo&arr=bar&bar=test&foo=1&obj=obj1&obj=obj2")
2 changes: 1 addition & 1 deletion tests/smoke_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ integration_test!(test_loader_empty, "test-loader");
integration_test!(test_units, "test-units");
integration_test!(test_rand, "test-rand");
integration_test!(test_yaml, "test-yaml");

integration_test!(test_glob, "test-glob");
integration_test!(test_regex, "test-regex");
integration_test!(test_urlquery, "test-urlquery");

/*
#[tokio::test]
Expand Down
25 changes: 25 additions & 0 deletions tests/snapshots/smoke_test__urlquery.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
source: tests/smoke_test.rs
expression: "test_policy(\"test-urlquery\", None).await.expect(\"error in test suite\")"
---
- result:
decode: "?foo=1&bar=test"
decode_object:
arr:
- foo
- bar
bar:
- test
foo:
- "1"
obj:
- obj1
- obj2
encode_1: "%3Ffoo%3D1%26bar%3Dtest"
encode_2: "&&&&"
encode_3: "===="
encode_4: "&=&="
encode_none: ""
encode_normaltext: abc
encode_object: arr=foo&arr=bar&bar=foo%26foo&foo=1&obj=obj1&obj=obj2

0 comments on commit f3e148b

Please sign in to comment.