Skip to content

Commit

Permalink
wasi-http: Make child fields immutable (bytecodealliance#7524)
Browse files Browse the repository at this point in the history
* Make child fields immutable

* Add `get_fields` and remove `FieldMapMutability`

Clean up the interface to immutable fields by adding a different
accessor.

* Clean up the diff
  • Loading branch information
elliottt authored and alexcrichton committed Nov 12, 2023
1 parent e6301d4 commit c11bc11
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use test_programs::wasi::http::types::{HeaderError, Headers};
use test_programs::wasi::http::types::{HeaderError, Headers, OutgoingRequest};

fn main() {
let hdrs = Headers::new();
Expand Down Expand Up @@ -57,4 +57,22 @@ fn main() {
Headers::from_list(&[("ok-header-name".to_owned(), b"bad\nvalue".to_vec())]),
Err(HeaderError::InvalidSyntax)
));

let req = OutgoingRequest::new(hdrs);
let hdrs = req.headers();

assert!(matches!(
hdrs.set(&"Content-Length".to_owned(), &[b"10".to_vec()]),
Err(HeaderError::Immutable),
));

assert!(matches!(
hdrs.append(&"Content-Length".to_owned(), &b"10".to_vec()),
Err(HeaderError::Immutable),
));

assert!(matches!(
hdrs.delete(&"Content-Length".to_owned()),
Err(HeaderError::Immutable),
));
}
64 changes: 36 additions & 28 deletions crates/wasi-http/src/types_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ fn move_fields(table: &mut Table, id: Resource<HostFields>) -> wasmtime::Result<
}
}

fn get_fields_mut<'a>(
fn get_fields<'a>(
table: &'a mut Table,
id: &Resource<HostFields>,
) -> wasmtime::Result<&'a mut FieldMap> {
) -> wasmtime::Result<&'a FieldMap> {
let fields = table.get(&id)?;
if let HostFields::Ref { parent, get_fields } = *fields {
let entry = table.get_any_mut(parent)?;
Expand All @@ -51,6 +51,16 @@ fn get_fields_mut<'a>(
}
}

fn get_fields_mut<'a>(
table: &'a mut Table,
id: &Resource<HostFields>,
) -> wasmtime::Result<Result<&'a mut FieldMap, types::HeaderError>> {
match table.get_mut(&id)? {
HostFields::Owned { fields } => Ok(Ok(fields)),
HostFields::Ref { .. } => Ok(Err(types::HeaderError::Immutable)),
}
}

fn is_forbidden_header<T: WasiHttpView>(view: &mut T, name: &HeaderName) -> bool {
static FORBIDDEN_HEADERS: [HeaderName; 9] = [
hyper::header::CONNECTION,
Expand Down Expand Up @@ -83,7 +93,7 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFields for T {
&mut self,
entries: Vec<(String, Vec<u8>)>,
) -> wasmtime::Result<Result<Resource<HostFields>, types::HeaderError>> {
let mut map = hyper::HeaderMap::new();
let mut fields = hyper::HeaderMap::new();

for (header, value) in entries {
let header = match hyper::header::HeaderName::from_bytes(header.as_bytes()) {
Expand All @@ -100,12 +110,12 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFields for T {
Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
};

map.append(header, value);
fields.append(header, value);
}

let id = self
.table()
.push(HostFields::Owned { fields: map })
.push(HostFields::Owned { fields })
.context("[new_fields] pushing fields")?;

Ok(Ok(id))
Expand All @@ -128,7 +138,7 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFields for T {
Err(_) => return Ok(vec![]),
};

let res = get_fields_mut(self.table(), &fields)
let res = get_fields(self.table(), &fields)
.context("[fields_get] getting fields")?
.get_all(header)
.into_iter()
Expand Down Expand Up @@ -160,14 +170,14 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFields for T {
}
}

let m =
get_fields_mut(self.table(), &fields).context("[fields_set] getting mutable fields")?;
m.remove(&header);
for value in values {
m.append(&header, value);
}

Ok(Ok(()))
Ok(get_fields_mut(self.table(), &fields)
.context("[fields_set] getting mutable fields")?
.map(|fields| {
fields.remove(&header);
for value in values {
fields.append(&header, value);
}
}))
}

fn delete(
Expand All @@ -184,9 +194,9 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFields for T {
return Ok(Err(types::HeaderError::Forbidden));
}

let m = get_fields_mut(self.table(), &fields)?;
m.remove(header);
Ok(Ok(()))
Ok(get_fields_mut(self.table(), &fields)?.map(|fields| {
fields.remove(header);
}))
}

fn append(
Expand All @@ -209,27 +219,25 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostFields for T {
Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
};

let m = get_fields_mut(self.table(), &fields)
.context("[fields_append] getting mutable fields")?;

m.append(header, value);
Ok(Ok(()))
Ok(get_fields_mut(self.table(), &fields)
.context("[fields_append] getting mutable fields")?
.map(|fields| {
fields.append(header, value);
}))
}

fn entries(
&mut self,
fields: Resource<HostFields>,
) -> wasmtime::Result<Vec<(String, Vec<u8>)>> {
let fields = get_fields_mut(self.table(), &fields)?;
let result = fields
Ok(get_fields(self.table(), &fields)?
.iter()
.map(|(name, value)| (name.as_str().to_owned(), value.as_bytes().to_owned()))
.collect();
Ok(result)
.collect())
}

fn clone(&mut self, fields: Resource<HostFields>) -> wasmtime::Result<Resource<HostFields>> {
let fields = get_fields_mut(self.table(), &fields)
let fields = get_fields(self.table(), &fields)
.context("[fields_clone] getting fields")?
.clone();

Expand Down Expand Up @@ -837,7 +845,7 @@ impl<T: WasiHttpView> crate::bindings::http::types::HostOutgoingBody for T {
.expect("outgoing-body trailer_sender consumed by a non-owning function");

let message = if let Some(ts) = ts {
FinishMessage::Trailers(get_fields_mut(self.table(), &ts)?.clone().into())
FinishMessage::Trailers(move_fields(self.table(), ts)?)
} else {
FinishMessage::Finished
};
Expand Down
1 change: 1 addition & 0 deletions crates/wasi-http/wit/deps/http/types.wit
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface types {
variant header-error {
invalid-syntax,
forbidden,
immutable
}

/// Field keys are always strings.
Expand Down
1 change: 1 addition & 0 deletions crates/wasi/wit/deps/http/types.wit
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface types {
variant header-error {
invalid-syntax,
forbidden,
immutable
}

/// Field keys are always strings.
Expand Down

0 comments on commit c11bc11

Please sign in to comment.