diff --git a/cli/tests/integration/edge_rate_limiting.rs b/cli/tests/integration/edge_rate_limiting.rs new file mode 100644 index 00000000..4a9e40de --- /dev/null +++ b/cli/tests/integration/edge_rate_limiting.rs @@ -0,0 +1,15 @@ +//! Tests related to HTTP request and response bodies. + +use { + crate::common::{Test, TestResult}, + hyper::StatusCode, +}; + +#[tokio::test(flavor = "multi_thread")] +async fn check_hostcalls_implemented() -> TestResult { + let resp = Test::using_fixture("edge-rate-limiting.wasm") + .against_empty() + .await?; + assert_eq!(resp.status(), StatusCode::OK); + Ok(()) +} diff --git a/cli/tests/integration/main.rs b/cli/tests/integration/main.rs index 95a3eab9..24fdf319 100644 --- a/cli/tests/integration/main.rs +++ b/cli/tests/integration/main.rs @@ -5,6 +5,7 @@ mod common; mod device_detection_lookup; mod dictionary_lookup; mod downstream_req; +mod edge_rate_limiting; mod env_vars; mod geolocation_lookup; mod grpc; diff --git a/lib/compute-at-edge-abi/compute-at-edge.witx b/lib/compute-at-edge-abi/compute-at-edge.witx index 953562c9..d2129f0f 100644 --- a/lib/compute-at-edge-abi/compute-at-edge.witx +++ b/lib/compute-at-edge-abi/compute-at-edge.witx @@ -640,6 +640,59 @@ ) ) +(module $fastly_erl + (@interface func (export "check_rate") + (param $rc string) + (param $entry string) + (param $delta u32) + (param $window u32) + (param $limit u32) + (param $pb string) + (param $ttl u32) + + (result $err (expected $blocked (error $fastly_status))) + ) + + (@interface func (export "ratecounter_increment") + (param $rc string) + (param $entry string) + (param $delta u32) + + (result $err (expected (error $fastly_status))) + ) + + (@interface func (export "ratecounter_lookup_rate") + (param $rc string) + (param $entry string) + (param $window u32) + + (result $err (expected $rate (error $fastly_status))) + ) + + (@interface func (export "ratecounter_lookup_count") + (param $rc string) + (param $entry string) + (param $duration u32) + + (result $err (expected $count (error $fastly_status))) + ) + + (@interface func (export "penaltybox_add") + (param $pb string) + (param $entry string) + (param $ttl u32) + + (result $err (expected (error $fastly_status))) + ) + + (@interface func (export "penaltybox_has") + (param $pb string) + (param $entry string) + + (result $err (expected $has (error $fastly_status))) + ) +) + (module $fastly_object_store (@interface func (export "open") (param $name string) diff --git a/lib/compute-at-edge-abi/typenames.witx b/lib/compute-at-edge-abi/typenames.witx index efecd946..e2b991e2 100644 --- a/lib/compute-at-edge-abi/typenames.witx +++ b/lib/compute-at-edge-abi/typenames.witx @@ -349,3 +349,8 @@ (field $dns_error_info_code u16) (field $tls_alert_id u8) )) + +(typename $blocked u32) +(typename $rate u32) +(typename $count u32) +(typename $has u32) diff --git a/lib/src/linking.rs b/lib/src/linking.rs index ea4eb616..6cd938a8 100644 --- a/lib/src/linking.rs +++ b/lib/src/linking.rs @@ -155,6 +155,7 @@ pub fn link_host_functions( wiggle_abi::fastly_config_store::add_to_linker(linker, WasmCtx::session)?; wiggle_abi::fastly_dictionary::add_to_linker(linker, WasmCtx::session)?; wiggle_abi::fastly_device_detection::add_to_linker(linker, WasmCtx::session)?; + wiggle_abi::fastly_erl::add_to_linker(linker, WasmCtx::session)?; wiggle_abi::fastly_geo::add_to_linker(linker, WasmCtx::session)?; wiggle_abi::fastly_http_body::add_to_linker(linker, WasmCtx::session)?; wiggle_abi::fastly_http_req::add_to_linker(linker, WasmCtx::session)?; diff --git a/lib/src/wiggle_abi.rs b/lib/src/wiggle_abi.rs index 8e1bee88..4bfd8820 100644 --- a/lib/src/wiggle_abi.rs +++ b/lib/src/wiggle_abi.rs @@ -56,6 +56,7 @@ mod config_store; mod device_detection_impl; mod dictionary_impl; mod entity; +mod erl_impl; mod fastly_purge_impl; mod geo_impl; mod headers; diff --git a/lib/src/wiggle_abi/erl_impl.rs b/lib/src/wiggle_abi/erl_impl.rs new file mode 100644 index 00000000..5074e9b3 --- /dev/null +++ b/lib/src/wiggle_abi/erl_impl.rs @@ -0,0 +1,62 @@ +use crate::{ + error::Error, session::Session, wiggle_abi::fastly_erl::FastlyErl, wiggle_abi::GuestPtr, +}; + +impl FastlyErl for Session { + fn check_rate( + &mut self, + _rc: &GuestPtr, + _entry: &GuestPtr, + _delta: u32, + _window: u32, + _limit: u32, + _pb: &GuestPtr, + _ttl: u32, + ) -> std::result::Result { + Ok(0) + } + + fn ratecounter_increment( + &mut self, + _rc: &GuestPtr, + _entry: &GuestPtr, + _delta: u32, + ) -> std::result::Result<(), Error> { + Ok(()) + } + + fn ratecounter_lookup_rate( + &mut self, + _rc: &GuestPtr, + _entry: &GuestPtr, + _window: u32, + ) -> std::result::Result { + Ok(0) + } + + fn ratecounter_lookup_count( + &mut self, + _rc: &GuestPtr, + _entry: &GuestPtr, + _duration: u32, + ) -> std::result::Result { + Ok(0) + } + + fn penaltybox_add( + &mut self, + _pb: &GuestPtr, + _entry: &GuestPtr, + _ttl: u32, + ) -> std::result::Result<(), Error> { + Ok(()) + } + + fn penaltybox_has( + &mut self, + _pb: &GuestPtr, + _entry: &GuestPtr, + ) -> std::result::Result { + Ok(0) + } +} diff --git a/test-fixtures/src/bin/edge-rate-limiting.rs b/test-fixtures/src/bin/edge-rate-limiting.rs new file mode 100644 index 00000000..91b18ac0 --- /dev/null +++ b/test-fixtures/src/bin/edge-rate-limiting.rs @@ -0,0 +1,33 @@ +//! A guest program to test that edge-rate-limiting API is implemented. + +//use std::time::Duration; + +//use fastly::erl::{CounterDuration, Penaltybox, RateCounter, RateWindow, ERL}; + +fn main() { +// let entry = "entry"; + +// let rc = RateCounter::open("rc"); +// let pb = Penaltybox::open("pb"); +// let erl = ERL::open(rc, pb); + +// let not_blocked = erl +// .check_rate(entry, 1, RateWindow::TenSecs, 100, Duration::from_secs(300)) +// .unwrap(); +// assert_eq!(not_blocked, false); + +// let rc2 = RateCounter::open("rc"); +// let rate_1 = rc2.lookup_rate(entry, RateWindow::OneSec).unwrap(); +// assert_eq!(rate_1, 0); + +// let count10 = rc2.lookup_count(entry, CounterDuration::TenSec).unwrap(); +// assert_eq!(count10, 0); + +// assert!(rc2.increment(entry, 600).is_ok()); + +// let pb2 = Penaltybox::open("pb"); +// let not_in_pb = pb2.has(entry).unwrap(); +// assert_eq!(not_in_pb, false); + +// assert!(pb2.add(entry, Duration::from_secs(300)).is_ok()); +}