Skip to content

Commit 8700ebd

Browse files
brendandburnspchickey
authored andcommitted
Make streams owned by request/response that they are tied to. (bytecodealliance#6228)
* Make streams owned by request/response that they are tied to. * Address comments, fix tests. * Address comment. * Update crates/wasi-http/src/streams_impl.rs Co-authored-by: Pat Hickey <pat@moreproductive.org> * Switch to BytesMut --------- Co-authored-by: Pat Hickey <pat@moreproductive.org>
1 parent 3effe3f commit 8700ebd

4 files changed

Lines changed: 68 additions & 26 deletions

File tree

crates/wasi-http/src/http_impl.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::r#struct::ActiveResponse;
2-
pub use crate::r#struct::WasiHttp;
2+
use crate::r#struct::{Stream, WasiHttp};
33
use crate::types::{RequestOptions, Scheme};
44
#[cfg(not(any(target_arch = "riscv64", target_arch = "s390x")))]
55
use anyhow::anyhow;
@@ -183,8 +183,10 @@ impl WasiHttp {
183183
let body = Full::<Bytes>::new(
184184
self.streams
185185
.get(&request.body)
186-
.unwrap_or(&Bytes::new())
187-
.clone(),
186+
.unwrap_or(&Stream::default())
187+
.data
188+
.clone()
189+
.freeze(),
188190
);
189191
let t = timeout(first_bytes_timeout, sender.send_request(call.body(body)?)).await?;
190192
let mut res = t?;
@@ -222,7 +224,7 @@ impl WasiHttp {
222224
}
223225
response.body = self.streams_id_base;
224226
self.streams_id_base = self.streams_id_base + 1;
225-
self.streams.insert(response.body, buf.freeze());
227+
self.streams.insert(response.body, buf.freeze().into());
226228
self.responses.insert(response_id, response);
227229
Ok(response_id)
228230
}

crates/wasi-http/src/streams_impl.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::poll::Pollable;
22
use crate::streams::{InputStream, OutputStream, StreamError};
33
use crate::WasiHttp;
44
use anyhow::{anyhow, bail};
5-
use bytes::BufMut;
65
use std::vec::Vec;
76

87
impl crate::streams::Host for WasiHttp {
@@ -11,10 +10,14 @@ impl crate::streams::Host for WasiHttp {
1110
stream: InputStream,
1211
len: u64,
1312
) -> wasmtime::Result<Result<(Vec<u8>, bool), StreamError>> {
14-
let s = self
13+
let st = self
1514
.streams
1615
.get_mut(&stream)
1716
.ok_or_else(|| anyhow!("stream not found: {stream}"))?;
17+
if st.closed {
18+
bail!("stream is dropped!");
19+
}
20+
let s = &mut st.data;
1821
if len == 0 {
1922
Ok(Ok((bytes::Bytes::new().to_vec(), s.len() > 0)))
2023
} else if s.len() > len.try_into()? {
@@ -31,10 +34,14 @@ impl crate::streams::Host for WasiHttp {
3134
stream: InputStream,
3235
len: u64,
3336
) -> wasmtime::Result<Result<(u64, bool), StreamError>> {
34-
let s = self
37+
let st = self
3538
.streams
3639
.get_mut(&stream)
3740
.ok_or_else(|| anyhow!("stream not found: {stream}"))?;
41+
if st.closed {
42+
bail!("stream is dropped!");
43+
}
44+
let s = &mut st.data;
3845
if len == 0 {
3946
Ok(Ok((0, s.len() > 0)))
4047
} else if s.len() > len.try_into()? {
@@ -52,7 +59,11 @@ impl crate::streams::Host for WasiHttp {
5259
}
5360

5461
fn drop_input_stream(&mut self, stream: InputStream) -> wasmtime::Result<()> {
55-
self.streams.remove(&stream);
62+
let st = self
63+
.streams
64+
.get_mut(&stream)
65+
.ok_or_else(|| anyhow!("stream not found: {stream}"))?;
66+
st.closed = true;
5667
Ok(())
5768
}
5869

@@ -61,18 +72,13 @@ impl crate::streams::Host for WasiHttp {
6172
this: OutputStream,
6273
buf: Vec<u8>,
6374
) -> wasmtime::Result<Result<u64, StreamError>> {
64-
match self.streams.get(&this) {
65-
Some(data) => {
66-
let mut new = bytes::BytesMut::with_capacity(data.len() + buf.len());
67-
new.put(data.clone());
68-
new.put(bytes::Bytes::from(buf.clone()));
69-
self.streams.insert(this, new.freeze());
70-
}
71-
None => {
72-
self.streams.insert(this, bytes::Bytes::from(buf.clone()));
73-
}
75+
let len = buf.len();
76+
let st = self.streams.entry(this).or_default();
77+
if st.closed {
78+
bail!("cannot write to closed stream");
7479
}
75-
Ok(Ok(buf.len().try_into()?))
80+
st.data.extend_from_slice(buf.as_slice());
81+
Ok(Ok(len.try_into()?))
7682
}
7783

7884
fn write_zeroes(
@@ -111,7 +117,11 @@ impl crate::streams::Host for WasiHttp {
111117
}
112118

113119
fn drop_output_stream(&mut self, stream: OutputStream) -> wasmtime::Result<()> {
114-
self.streams.remove(&stream);
120+
let st = self
121+
.streams
122+
.get_mut(&stream)
123+
.ok_or_else(|| anyhow!("stream not found: {stream}"))?;
124+
st.closed = true;
115125
Ok(())
116126
}
117127
}

crates/wasi-http/src/struct.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
use crate::types::{Method, Scheme};
2-
use bytes::Bytes;
2+
use bytes::{BufMut, Bytes, BytesMut};
33
use std::collections::HashMap;
44

5+
#[derive(Clone, Default)]
6+
pub struct Stream {
7+
pub closed: bool,
8+
pub data: BytesMut,
9+
}
10+
511
#[derive(Clone)]
612
pub struct WasiHttp {
713
pub request_id_base: u32,
@@ -11,7 +17,7 @@ pub struct WasiHttp {
1117
pub requests: HashMap<u32, ActiveRequest>,
1218
pub responses: HashMap<u32, ActiveResponse>,
1319
pub fields: HashMap<u32, HashMap<String, Vec<String>>>,
14-
pub streams: HashMap<u32, Bytes>,
20+
pub streams: HashMap<u32, Stream>,
1521
}
1622

1723
#[derive(Clone)]
@@ -66,6 +72,23 @@ impl ActiveResponse {
6672
}
6773
}
6874

75+
impl Stream {
76+
pub fn new() -> Self {
77+
Self::default()
78+
}
79+
}
80+
81+
impl From<Bytes> for Stream {
82+
fn from(bytes: Bytes) -> Self {
83+
let mut buf = BytesMut::with_capacity(bytes.len());
84+
buf.put(bytes);
85+
Self {
86+
closed: false,
87+
data: buf,
88+
}
89+
}
90+
}
91+
6992
impl WasiHttp {
7093
pub fn new() -> Self {
7194
Self {

crates/wasi-http/src/types_impl.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use crate::poll::Pollable;
2-
use crate::r#struct::ActiveRequest;
2+
use crate::r#struct::{ActiveRequest, Stream};
33
use crate::types::{
44
Error, Fields, FutureIncomingResponse, Headers, IncomingRequest, IncomingResponse,
55
IncomingStream, Method, OutgoingRequest, OutgoingResponse, OutgoingStream, ResponseOutparam,
66
Scheme, StatusCode, Trailers,
77
};
88
use crate::WasiHttp;
99
use anyhow::{anyhow, bail};
10-
use std::collections::HashMap;
10+
use std::collections::{hash_map::Entry, HashMap};
1111

1212
impl crate::types::Host for WasiHttp {
1313
fn drop_fields(&mut self, fields: Fields) -> wasmtime::Result<()> {
@@ -123,7 +123,10 @@ impl crate::types::Host for WasiHttp {
123123
bail!("unimplemented: drop_incoming_request")
124124
}
125125
fn drop_outgoing_request(&mut self, request: OutgoingRequest) -> wasmtime::Result<()> {
126-
self.requests.remove(&request);
126+
if let Entry::Occupied(e) = self.requests.entry(request) {
127+
let r = e.remove();
128+
self.streams.remove(&r.body);
129+
}
127130
Ok(())
128131
}
129132
fn incoming_request_method(&mut self, _request: IncomingRequest) -> wasmtime::Result<Method> {
@@ -192,6 +195,7 @@ impl crate::types::Host for WasiHttp {
192195
if req.body == 0 {
193196
req.body = self.streams_id_base;
194197
self.streams_id_base = self.streams_id_base + 1;
198+
self.streams.insert(req.body, Stream::default());
195199
}
196200
Ok(Ok(req.body))
197201
}
@@ -206,7 +210,10 @@ impl crate::types::Host for WasiHttp {
206210
bail!("unimplemented: set_response_outparam")
207211
}
208212
fn drop_incoming_response(&mut self, response: IncomingResponse) -> wasmtime::Result<()> {
209-
self.responses.remove(&response);
213+
if let Entry::Occupied(e) = self.responses.entry(response) {
214+
let r = e.remove();
215+
self.streams.remove(&r.body);
216+
}
210217
Ok(())
211218
}
212219
fn drop_outgoing_response(&mut self, _response: OutgoingResponse) -> wasmtime::Result<()> {

0 commit comments

Comments
 (0)