Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Unreleased

- Add adapter shim for `async-io.select`-incompatible handles. ([#600](https://github.com/fastly/Viceroy/pull/600))
- Add stub implementations for resvpnproxy hostcalls.

## 0.16.5 (2026-03-23)
Expand Down
1 change: 1 addition & 0 deletions src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub(crate) mod bindings {
"fastly:compute/kv-store.[method]store.list-async": async | tracing,
"fastly:compute/kv-store.[method]store.lookup": async | tracing,
"fastly:compute/kv-store.[method]store.lookup-async": async | tracing,
"fastly:compute/http-cache.[method]entry.subscribe": tracing | trappable,
"fastly:compute/http-downstream.next-request": async | tracing,
"fastly:compute/http-body.read": async | tracing,
"fastly:compute/backend.register-dynamic-backend": async | tracing,
Expand Down
29 changes: 25 additions & 4 deletions src/component/compute/async_io.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use {
crate::component::bindings::fastly::compute::async_io,
crate::{
component::bindings::fastly::compute::async_io,
linking::{ComponentCtx, SessionView},
session::AsyncItem,
wiggle_abi,
},
anyhow::bail,
Expand Down Expand Up @@ -56,13 +57,33 @@ impl async_io::HostPollable for ComponentCtx {
.is_some()
}

fn drop(&mut self, handle: Resource<async_io::Pollable>) -> wasmtime::Result<()> {
let handle = wiggle_abi::types::AsyncItemHandle::from(handle).into();
fn drop(&mut self, h: Resource<async_io::Pollable>) -> wasmtime::Result<()> {
let handle: wiggle_abi::types::AsyncItemHandle = h.into();

{
let it = self.session_mut().async_item_mut(handle.into())?;

// In the WIT ABI, CacheEntry, CacheReplace, and HttpCacheEntry AsyncItems are not
// async_io::Pollables. Insteady, their primary handles "own" the AsyncItem,
// and the Pollable "borrows" from it.
//
// But! Those handles have the same ID when presented to the host.
// So if we encounter a Pollable to one of those types here, we need to keep
// the AsyncItem in the table, and just let drop() clean up the Resource.
//
// Note that we don't cover HTTP cache items here; we don't support the HTTP caching
// API, so the guest won't have a valid handle to an HTTP cache item.
if matches!(*it, AsyncItem::PendingCache(_)) {
// Don't remove from the session.async_items set; this is "just" the Pollable for the
// item, not the real thing.
return Ok(());
};
}

// Use `.take_async_item` instead of manipulating
// `self.session_mut().async_items` directly, so that any extra state
// associated with the item is also cleared.
let _ = self.session_mut().take_async_item(handle).unwrap();
let _ = self.session_mut().take_async_item(handle.into())?;

Ok(())
}
Expand Down
16 changes: 14 additions & 2 deletions src/component/compute/cache.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use {
crate::component::bindings::fastly::compute::{cache as api, http_body, types},
crate::{
body::Body,
cache::{self, CacheKey, SurrogateKeySet, VaryRule, WriteOptions},
component::bindings::fastly::compute::{cache as api, http_body, types},
error::Error,
linking::{ComponentCtx, SessionView},
session::{PeekableTask, PendingCacheTask, Session},
wiggle_abi::types::{CacheBusyHandle, CacheHandle},
wiggle_abi::types::{CacheBusyHandle, CacheHandle, CacheReplaceHandle},
},
bytes::Bytes,
http::HeaderMap,
Expand Down Expand Up @@ -294,6 +294,12 @@ impl api::HostReplaceEntry for ComponentCtx {
.into())
}

fn subscribe(&mut self, handle: Resource<api::ReplaceEntry>) -> Resource<api::Pollable> {
let host_handle = crate::session::AsyncItemHandle::from(CacheReplaceHandle::from(handle));
let guest_handle = crate::wiggle_abi::types::AsyncItemHandle::from(host_handle);
guest_handle.into()
}

fn drop(&mut self, _entry: Resource<api::ReplaceEntry>) -> wasmtime::Result<()> {
Ok(())
}
Expand Down Expand Up @@ -594,6 +600,12 @@ impl api::HostEntry for ComponentCtx {
.into())
}

fn subscribe(&mut self, handle: Resource<api::Entry>) -> Resource<api::Pollable> {
let host_handle = crate::session::AsyncItemHandle::from(CacheHandle::from(handle));
let guest_handle = crate::wiggle_abi::types::AsyncItemHandle::from(host_handle);
guest_handle.into()
}

fn drop(&mut self, _entry: Resource<api::Entry>) -> wasmtime::Result<()> {
Ok(())
}
Expand Down
12 changes: 11 additions & 1 deletion src/component/compute/http_cache.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use {
crate::component::bindings::fastly::compute::{http_body, http_cache, types},
crate::component::bindings::fastly::compute::{async_io, http_body, http_cache, types},
crate::{error::Error, linking::ComponentCtx},
wasmtime::component::Resource,
};
Expand Down Expand Up @@ -350,6 +350,16 @@ impl http_cache::HostEntry for ComponentCtx {
.into())
}

fn subscribe(
&mut self,
_handle: Resource<http_cache::Entry>,
) -> Result<Resource<async_io::Pollable>, anyhow::Error> {
Err(Error::Unsupported {
msg: "HTTP Cache API primitives not yet supported",
}
.into())
}

fn drop(&mut self, _handle: Resource<http_cache::Entry>) -> wasmtime::Result<()> {
Err(Error::Unsupported {
msg: "HTTP Cache API primitives not yet supported",
Expand Down
5 changes: 4 additions & 1 deletion src/component/compute/http_resp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
component::{
bindings::fastly::compute::{http_body, http_resp, http_types, types},
compute::headers::{get_names, get_values},
compute::headers::get_names,
},
error::Error,
linking::{ComponentCtx, SessionView},
Expand All @@ -15,6 +15,9 @@ use {
wasmtime::component::Resource,
};

#[allow(unused)] // Conditionally unused in the trap test. Quiet the warning.
use crate::component::compute::headers::get_values;

const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;

impl http_resp::Host for ComponentCtx {
Expand Down
16 changes: 15 additions & 1 deletion src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use std::time::Duration;
use crate::cache::{Cache, CacheEntry};
use crate::linking::Limiter;
use crate::object_store::KvStoreError;
use crate::wiggle_abi::types::{CacheBusyHandle, CacheHandle, FramingHeadersMode};
use crate::wiggle_abi::types::{
CacheBusyHandle, CacheHandle, CacheReplaceHandle, FramingHeadersMode,
};

use {
self::downstream::DownstreamResponseState,
Expand Down Expand Up @@ -1577,6 +1579,18 @@ impl From<CacheHandle> for AsyncItemHandle {
}
}

impl From<AsyncItemHandle> for CacheReplaceHandle {
fn from(h: AsyncItemHandle) -> CacheReplaceHandle {
CacheReplaceHandle::from(h.as_u32())
}
}

impl From<CacheReplaceHandle> for AsyncItemHandle {
fn from(h: CacheReplaceHandle) -> AsyncItemHandle {
AsyncItemHandle::from_u32(h.into())
}
}

impl From<AsyncItemHandle> for CacheBusyHandle {
fn from(h: AsyncItemHandle) -> CacheBusyHandle {
CacheBusyHandle::from(h.as_u32())
Expand Down
Loading
Loading