From 9ab65ba83124d9e94674aa178bf9b76e609c3037 Mon Sep 17 00:00:00 2001 From: Ulyssa Date: Wed, 3 Jul 2024 09:47:06 -0700 Subject: [PATCH 1/2] Add `downstream_compliance_region` hostcall --- crates/adapter/src/fastly/core.rs | 4 +-- lib/compute-at-edge-abi/compute-at-edge.witx | 9 ++++++- lib/src/component/http_req.rs | 7 ++--- lib/src/wiggle_abi/req_impl.rs | 27 ++++++++++++++++++++ lib/wit/deps/fastly/compute.wit | 2 +- 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/crates/adapter/src/fastly/core.rs b/crates/adapter/src/fastly/core.rs index 493d3cc0..e613905e 100644 --- a/crates/adapter/src/fastly/core.rs +++ b/crates/adapter/src/fastly/core.rs @@ -995,9 +995,7 @@ pub mod fastly_http_req { nwritten: *mut usize, ) -> FastlyStatus { alloc_result!(region_out, region_max_len, nwritten, { - fastly::api::http_req::downstream_compliance_region( - u64::try_from(region_max_len).trapping_unwrap(), - ) + fastly::api::http_req::downstream_compliance_region() }) } diff --git a/lib/compute-at-edge-abi/compute-at-edge.witx b/lib/compute-at-edge-abi/compute-at-edge.witx index 3306aac3..5aa0731d 100644 --- a/lib/compute-at-edge-abi/compute-at-edge.witx +++ b/lib/compute-at-edge-abi/compute-at-edge.witx @@ -242,7 +242,14 @@ (param $ja4_max_len (@witx usize)) (param $nwritten_out (@witx pointer (@witx usize))) (result $err (expected (error $fastly_status))) - ) + ) + + (@interface func (export "downstream_compliance_region") + (param $region_out (@witx pointer (@witx char8))) + (param $region_max_len (@witx usize)) + (param $nwritten_out (@witx pointer (@witx usize))) + (result $err (expected (error $fastly_status))) + ) (@interface func (export "new") (result $err (expected $request_handle (error $fastly_status))) diff --git a/lib/src/component/http_req.rs b/lib/src/component/http_req.rs index 9e64fa47..902e9fd9 100644 --- a/lib/src/component/http_req.rs +++ b/lib/src/component/http_req.rs @@ -808,11 +808,8 @@ impl http_req::Host for Session { Err(Error::NotAvailable("Client TLS JA4 hash").into()) } - async fn downstream_compliance_region( - &mut self, - _max_len: u64, - ) -> Result, types::Error> { - Err(Error::NotAvailable("Client TLS JA4 hash").into()) + async fn downstream_compliance_region(&mut self) -> Result, types::Error> { + Ok(Vec::from(b"none")) } async fn original_header_names_get( diff --git a/lib/src/wiggle_abi/req_impl.rs b/lib/src/wiggle_abi/req_impl.rs index 8af66e2e..954923bc 100644 --- a/lib/src/wiggle_abi/req_impl.rs +++ b/lib/src/wiggle_abi/req_impl.rs @@ -300,6 +300,33 @@ impl FastlyHttpReq for Session { Err(Error::NotAvailable("Client TLS JA4 hash")) } + fn downstream_compliance_region( + &mut self, + memory: &mut GuestMemory<'_>, + // Must be a 16-byte array: + region_out: GuestPtr, + region_max_len: u32, + nwritten_out: GuestPtr, + ) -> Result<(), Error> { + const REGION_NONE: &[u8] = b"none"; + const REGION_NONE_LEN: u32 = 4; + + if region_max_len < REGION_NONE_LEN { + // Let the guest know how much we want to write. + memory.write(nwritten_out, REGION_NONE_LEN)?; + + return Err(Error::BufferLengthError { + buf: "region_out", + len: "region_max_len", + }); + } + + memory.copy_from_slice(REGION_NONE, region_out.as_array(region_max_len))?; + memory.write(nwritten_out, REGION_NONE_LEN)?; + + Ok(()) + } + fn framing_headers_mode_set( &mut self, _memory: &mut GuestMemory<'_>, diff --git a/lib/wit/deps/fastly/compute.wit b/lib/wit/deps/fastly/compute.wit index a7dcb7ce..d52a8be3 100644 --- a/lib/wit/deps/fastly/compute.wit +++ b/lib/wit/deps/fastly/compute.wit @@ -323,7 +323,7 @@ interface http-req { downstream-tls-ja4: func(max-len: u64) -> result, error>; - downstream-compliance-region: func(max-len: u64) -> result, error>; + downstream-compliance-region: func() -> result, error>; new: func() -> result; From 656a5a94ec7eaeebd6d80bcba839d89afe0bfbc1 Mon Sep 17 00:00:00 2001 From: Ulyssa Date: Fri, 26 Jul 2024 13:25:56 -0700 Subject: [PATCH 2/2] Update for review feedback --- crates/adapter/src/fastly/core.rs | 4 +++- lib/src/component/http_req.rs | 13 +++++++++++-- lib/src/session.rs | 13 +++++++++++++ lib/src/wiggle_abi/req_impl.rs | 30 ++++++++++++++++-------------- lib/wit/deps/fastly/compute.wit | 2 +- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/crates/adapter/src/fastly/core.rs b/crates/adapter/src/fastly/core.rs index e613905e..493d3cc0 100644 --- a/crates/adapter/src/fastly/core.rs +++ b/crates/adapter/src/fastly/core.rs @@ -995,7 +995,9 @@ pub mod fastly_http_req { nwritten: *mut usize, ) -> FastlyStatus { alloc_result!(region_out, region_max_len, nwritten, { - fastly::api::http_req::downstream_compliance_region() + fastly::api::http_req::downstream_compliance_region( + u64::try_from(region_max_len).trapping_unwrap(), + ) }) } diff --git a/lib/src/component/http_req.rs b/lib/src/component/http_req.rs index 902e9fd9..32fb6841 100644 --- a/lib/src/component/http_req.rs +++ b/lib/src/component/http_req.rs @@ -808,8 +808,17 @@ impl http_req::Host for Session { Err(Error::NotAvailable("Client TLS JA4 hash").into()) } - async fn downstream_compliance_region(&mut self) -> Result, types::Error> { - Ok(Vec::from(b"none")) + async fn downstream_compliance_region( + &mut self, + region_max_len: u64, + ) -> Result, types::Error> { + let region = Session::downstream_compliance_region(self); + let region_len = region.len(); + + match u64::try_from(region_len) { + Ok(region_len) if region_len <= region_max_len => Ok(region.into()), + too_large => Err(types::Error::BufferLen(too_large.unwrap_or(0))), + } } async fn original_header_names_get( diff --git a/lib/src/session.rs b/lib/src/session.rs index 754d8f2e..8b1b5615 100644 --- a/lib/src/session.rs +++ b/lib/src/session.rs @@ -38,6 +38,8 @@ use { tokio::sync::oneshot::Sender, }; +const REGION_NONE: &[u8] = b"none"; + /// Data specific to an individual request, including any host-side /// allocations on behalf of the guest processing the request. pub struct Session { @@ -45,6 +47,11 @@ pub struct Session { downstream_client_addr: SocketAddr, /// The IP address and port that received this session. downstream_server_addr: SocketAddr, + /// The compliance region that this request was received in. + /// + /// For now this is just always `"none"`, but we place the field in the session + /// to make it easier to implement custom configuration values later on. + downstream_compliance_region: Vec, /// Handle for the downstream request "parts". NB the backing parts data can be mutated /// or even removed from the relevant map. downstream_req_handle: RequestHandle, @@ -165,6 +172,7 @@ impl Session { Session { downstream_server_addr: server_addr, downstream_client_addr: client_addr, + downstream_compliance_region: Vec::from(REGION_NONE), downstream_req_handle, downstream_req_body_handle, downstream_req_original_headers, @@ -204,6 +212,11 @@ impl Session { self.downstream_server_addr.ip() } + /// Retrieve the compliance region that received the request for this session. + pub fn downstream_compliance_region(&self) -> &[u8] { + self.downstream_compliance_region.as_slice() + } + /// Retrieve the handle corresponding to the downstream request. pub fn downstream_request(&self) -> RequestHandle { self.downstream_req_handle diff --git a/lib/src/wiggle_abi/req_impl.rs b/lib/src/wiggle_abi/req_impl.rs index 954923bc..23cd1ce8 100644 --- a/lib/src/wiggle_abi/req_impl.rs +++ b/lib/src/wiggle_abi/req_impl.rs @@ -308,23 +308,25 @@ impl FastlyHttpReq for Session { region_max_len: u32, nwritten_out: GuestPtr, ) -> Result<(), Error> { - const REGION_NONE: &[u8] = b"none"; - const REGION_NONE_LEN: u32 = 4; + let region = Session::downstream_compliance_region(self); + let region_len = region.len(); - if region_max_len < REGION_NONE_LEN { - // Let the guest know how much we want to write. - memory.write(nwritten_out, REGION_NONE_LEN)?; + match u32::try_from(region_len) { + Ok(region_len) if region_len <= region_max_len => { + memory.copy_from_slice(region, region_out.as_array(region_max_len))?; + memory.write(nwritten_out, region_len.try_into().unwrap_or(0))?; - return Err(Error::BufferLengthError { - buf: "region_out", - len: "region_max_len", - }); - } - - memory.copy_from_slice(REGION_NONE, region_out.as_array(region_max_len))?; - memory.write(nwritten_out, REGION_NONE_LEN)?; + Ok(()) + } + too_large => { + memory.write(nwritten_out, too_large.unwrap_or(0))?; - Ok(()) + Err(Error::BufferLengthError { + buf: "region_out", + len: "region_max_len", + }) + } + } } fn framing_headers_mode_set( diff --git a/lib/wit/deps/fastly/compute.wit b/lib/wit/deps/fastly/compute.wit index d52a8be3..a7dcb7ce 100644 --- a/lib/wit/deps/fastly/compute.wit +++ b/lib/wit/deps/fastly/compute.wit @@ -323,7 +323,7 @@ interface http-req { downstream-tls-ja4: func(max-len: u64) -> result, error>; - downstream-compliance-region: func() -> result, error>; + downstream-compliance-region: func(max-len: u64) -> result, error>; new: func() -> result;