Skip to main content

wasmtime_wasi_http/p3/host/
types.rs

1use crate::FieldMap;
2use crate::p3::bindings::clocks::monotonic_clock::Duration;
3use crate::p3::bindings::http::types::{
4    ErrorCode, FieldName, FieldValue, Fields, HeaderError, Headers, Host, HostFields, HostRequest,
5    HostRequestOptions, HostRequestWithStore, HostResponse, HostResponseWithStore, Method, Request,
6    RequestOptions, RequestOptionsError, Response, Scheme, StatusCode, Trailers,
7};
8use crate::p3::body::Body;
9use crate::p3::{HeaderResult, HttpError, RequestOptionsResult};
10use crate::{WasiHttp, WasiHttpCtxView};
11use std::sync::Arc;
12use wasmtime::AsContextMut;
13use wasmtime::component::{Access, FutureReader, Resource, ResourceTable, StreamReader};
14use wasmtime::error::Context as _;
15
16fn get_fields<'a>(
17    table: &'a ResourceTable,
18    fields: &Resource<Fields>,
19) -> wasmtime::Result<&'a Fields> {
20    table
21        .get(&fields)
22        .context("failed to get fields from table")
23}
24
25fn get_fields_mut<'a>(
26    table: &'a mut ResourceTable,
27    fields: &Resource<Fields>,
28) -> HeaderResult<&'a mut Fields> {
29    table
30        .get_mut(&fields)
31        .context("failed to get fields from table")
32        .map_err(crate::p3::HeaderError::trap)
33}
34
35fn push_fields(table: &mut ResourceTable, fields: Fields) -> wasmtime::Result<Resource<Fields>> {
36    table.push(fields).context("failed to push fields to table")
37}
38
39fn delete_fields(table: &mut ResourceTable, fields: Resource<Fields>) -> wasmtime::Result<Fields> {
40    let mut fields = table
41        .delete(fields)
42        .context("failed to delete fields from table")?;
43    // When fields are passed by ownership to the host that flags them as
44    // immutable within `wasi:http`, and this semantically means that putting
45    // fields in a request, then getting them back out, will return an immutable
46    // view of the headers rather than mutable for example.
47    fields.set_immutable();
48    Ok(fields)
49}
50
51fn get_request<'a>(
52    table: &'a ResourceTable,
53    req: &Resource<Request>,
54) -> wasmtime::Result<&'a Request> {
55    table.get(req).context("failed to get request from table")
56}
57
58fn get_request_mut<'a>(
59    table: &'a mut ResourceTable,
60    req: &Resource<Request>,
61) -> wasmtime::Result<&'a mut Request> {
62    table
63        .get_mut(req)
64        .context("failed to get request from table")
65}
66
67fn get_response<'a>(
68    table: &'a ResourceTable,
69    res: &Resource<Response>,
70) -> wasmtime::Result<&'a Response> {
71    table.get(res).context("failed to get response from table")
72}
73
74fn get_response_mut<'a>(
75    table: &'a mut ResourceTable,
76    res: &Resource<Response>,
77) -> wasmtime::Result<&'a mut Response> {
78    table
79        .get_mut(res)
80        .context("failed to get response from table")
81}
82
83fn get_request_options<'a>(
84    table: &'a ResourceTable,
85    opts: &Resource<RequestOptions>,
86) -> wasmtime::Result<&'a RequestOptions> {
87    table
88        .get(opts)
89        .context("failed to get request options from table")
90}
91
92fn get_request_options_mut<'a>(
93    table: &'a mut ResourceTable,
94    opts: &Resource<RequestOptions>,
95) -> RequestOptionsResult<&'a mut RequestOptions> {
96    table
97        .get_mut(opts)
98        .context("failed to get request options from table")
99        .map_err(crate::p3::RequestOptionsError::trap)
100}
101
102fn push_request_options(
103    table: &mut ResourceTable,
104    opts: RequestOptions,
105) -> wasmtime::Result<Resource<RequestOptions>> {
106    table
107        .push(opts)
108        .context("failed to push request options to table")
109}
110
111fn delete_request_options(
112    table: &mut ResourceTable,
113    opts: Resource<RequestOptions>,
114) -> wasmtime::Result<RequestOptions> {
115    table
116        .delete(opts)
117        .context("failed to delete request options from table")
118}
119
120impl HostFields for WasiHttpCtxView<'_> {
121    fn new(&mut self) -> wasmtime::Result<Resource<Fields>> {
122        push_fields(self.table, FieldMap::new_mutable(self.ctx.field_size_limit))
123    }
124
125    fn from_list(
126        &mut self,
127        entries: Vec<(FieldName, FieldValue)>,
128    ) -> HeaderResult<Resource<Fields>> {
129        let mut fields = FieldMap::new_mutable(self.ctx.field_size_limit);
130        for (name, value) in entries {
131            fields.append(self.hooks, name, value)?;
132        }
133        let fields = push_fields(self.table, fields).map_err(crate::p3::HeaderError::trap)?;
134        Ok(fields)
135    }
136
137    fn get(
138        &mut self,
139        fields: Resource<Fields>,
140        name: FieldName,
141    ) -> wasmtime::Result<Vec<FieldValue>> {
142        let fields = get_fields(self.table, &fields)?;
143        Ok(fields
144            .get_all(name)
145            .into_iter()
146            .map(|val| val.as_bytes().into())
147            .collect())
148    }
149
150    fn has(&mut self, fields: Resource<Fields>, name: FieldName) -> wasmtime::Result<bool> {
151        let fields = get_fields(self.table, &fields)?;
152        Ok(fields.contains_key(name))
153    }
154
155    fn set(
156        &mut self,
157        fields: Resource<Fields>,
158        name: FieldName,
159        values: Vec<FieldValue>,
160    ) -> HeaderResult<()> {
161        get_fields_mut(self.table, &fields)?.set(self.hooks, name, values)?;
162        Ok(())
163    }
164
165    fn delete(&mut self, fields: Resource<Fields>, name: FieldName) -> HeaderResult<()> {
166        get_fields_mut(self.table, &fields)?.remove_all(self.hooks, name)?;
167        Ok(())
168    }
169
170    fn get_and_delete(
171        &mut self,
172        fields: Resource<Fields>,
173        name: FieldName,
174    ) -> HeaderResult<Vec<FieldValue>> {
175        let name = name.parse().or(Err(HeaderError::InvalidSyntax))?;
176        let values = get_fields_mut(self.table, &fields)?
177            .remove_all(self.hooks, name)?
178            .into_iter();
179        Ok(values.map(|value| value.as_bytes().into()).collect())
180    }
181
182    fn append(
183        &mut self,
184        fields: Resource<Fields>,
185        name: FieldName,
186        value: FieldValue,
187    ) -> HeaderResult<()> {
188        get_fields_mut(self.table, &fields)?.append(self.hooks, name, value)?;
189        Ok(())
190    }
191
192    fn copy_all(
193        &mut self,
194        fields: Resource<Fields>,
195    ) -> wasmtime::Result<Vec<(FieldName, FieldValue)>> {
196        let fields = get_fields(self.table, &fields)?;
197        let fields = fields
198            .iter()
199            .map(|(name, value)| (name.as_str().into(), value.as_bytes().into()))
200            .collect();
201        Ok(fields)
202    }
203
204    fn clone(&mut self, fields: Resource<Fields>) -> wasmtime::Result<Resource<Fields>> {
205        let mut fields = get_fields(self.table, &fields)?.clone();
206        fields.set_mutable(self.ctx.field_size_limit);
207        push_fields(self.table, fields)
208    }
209
210    fn drop(&mut self, fields: Resource<Fields>) -> wasmtime::Result<()> {
211        delete_fields(self.table, fields)?;
212        Ok(())
213    }
214}
215
216fn new_request<S>(
217    mut store: S,
218    mut getter: impl FnMut(&mut S::Data) -> WasiHttpCtxView<'_> + Copy + Send + 'static,
219    headers: Resource<Headers>,
220    contents: Option<StreamReader<u8>>,
221    trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
222    options: Option<Resource<RequestOptions>>,
223) -> wasmtime::Result<(Resource<Request>, FutureReader<Result<(), ErrorCode>>)>
224where
225    S: AsContextMut,
226{
227    let mut store = store.as_context_mut();
228    let (body, body_result) = Body::new_guest(&mut store, getter, contents, trailers)?;
229    let cx = getter(store.data_mut());
230    let headers = delete_fields(cx.table, headers)?;
231    let options = options
232        .map(|options| delete_request_options(cx.table, options))
233        .transpose()?;
234    let req = Request {
235        method: http::Method::GET,
236        scheme: None,
237        authority: None,
238        path_with_query: None,
239        headers,
240        options: options.map(Into::into),
241        body,
242    };
243    let req = cx
244        .table
245        .push(req)
246        .context("failed to push request to table")?;
247    Ok((req, body_result))
248}
249
250impl<T> HostRequestWithStore<T> for WasiHttp {
251    fn new(
252        store: Access<T, Self>,
253        headers: Resource<Headers>,
254        contents: Option<StreamReader<u8>>,
255        trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
256        options: Option<Resource<RequestOptions>>,
257    ) -> wasmtime::Result<(Resource<Request>, FutureReader<Result<(), ErrorCode>>)> {
258        let getter = store.getter();
259        new_request(store, getter, headers, contents, trailers, options)
260    }
261
262    fn consume_body(
263        mut store: Access<T, Self>,
264        req: Resource<Request>,
265        fut: FutureReader<Result<(), ErrorCode>>,
266    ) -> wasmtime::Result<(
267        StreamReader<u8>,
268        FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
269    )> {
270        let getter = store.getter();
271        let Request { body, .. } = store.get().table.delete(req)?;
272        body.consume(store, fut, getter)
273    }
274
275    fn drop(mut store: Access<'_, T, Self>, req: Resource<Request>) -> wasmtime::Result<()> {
276        let Request { body, .. } = store.get().table.delete(req)?;
277        body.drop(store)?;
278        Ok(())
279    }
280}
281
282impl HostRequest for WasiHttpCtxView<'_> {
283    fn get_method(&mut self, req: Resource<Request>) -> wasmtime::Result<Method> {
284        let Request { method, .. } = get_request(self.table, &req)?;
285        Ok(method.into())
286    }
287
288    fn set_method(
289        &mut self,
290        req: Resource<Request>,
291        method: Method,
292    ) -> wasmtime::Result<Result<(), ()>> {
293        let req = get_request_mut(self.table, &req)?;
294        let Ok(method) = method.try_into() else {
295            return Ok(Err(()));
296        };
297        req.method = method;
298        Ok(Ok(()))
299    }
300
301    fn get_path_with_query(&mut self, req: Resource<Request>) -> wasmtime::Result<Option<String>> {
302        let Request {
303            path_with_query, ..
304        } = get_request(self.table, &req)?;
305        Ok(path_with_query.as_ref().map(|pq| pq.as_str().into()))
306    }
307
308    fn set_path_with_query(
309        &mut self,
310        req: Resource<Request>,
311        path_with_query: Option<String>,
312    ) -> wasmtime::Result<Result<(), ()>> {
313        let req = get_request_mut(self.table, &req)?;
314
315        let Some(path_with_query) = path_with_query else {
316            req.path_with_query = None;
317            return Ok(Ok(()));
318        };
319        let Some(path_with_query) = crate::parse_path_with_query(&path_with_query) else {
320            return Ok(Err(()));
321        };
322        req.path_with_query = Some(path_with_query);
323        Ok(Ok(()))
324    }
325
326    fn get_scheme(&mut self, req: Resource<Request>) -> wasmtime::Result<Option<Scheme>> {
327        let Request { scheme, .. } = get_request(self.table, &req)?;
328        Ok(scheme.as_ref().map(Into::into))
329    }
330
331    fn set_scheme(
332        &mut self,
333        req: Resource<Request>,
334        scheme: Option<Scheme>,
335    ) -> wasmtime::Result<Result<(), ()>> {
336        let req = get_request_mut(self.table, &req)?;
337        let Some(scheme) = scheme else {
338            req.scheme = None;
339            return Ok(Ok(()));
340        };
341        let Ok(scheme) = scheme.try_into() else {
342            return Ok(Err(()));
343        };
344        req.scheme = Some(scheme);
345        Ok(Ok(()))
346    }
347
348    fn get_authority(&mut self, req: Resource<Request>) -> wasmtime::Result<Option<String>> {
349        let Request { authority, .. } = get_request(self.table, &req)?;
350        Ok(authority.as_ref().map(|auth| auth.as_str().into()))
351    }
352
353    fn set_authority(
354        &mut self,
355        req: Resource<Request>,
356        authority: Option<String>,
357    ) -> wasmtime::Result<Result<(), ()>> {
358        let req = get_request_mut(self.table, &req)?;
359        let Some(authority) = authority else {
360            req.authority = None;
361            return Ok(Ok(()));
362        };
363        let Ok(authority) = crate::parse_authority(authority) else {
364            return Ok(Err(()));
365        };
366        req.authority = Some(authority);
367        Ok(Ok(()))
368    }
369
370    fn get_options(
371        &mut self,
372        req: Resource<Request>,
373    ) -> wasmtime::Result<Option<Resource<RequestOptions>>> {
374        let Request { options, .. } = get_request(self.table, &req)?;
375        if let Some(options) = options {
376            let options = push_request_options(
377                self.table,
378                RequestOptions::new_immutable(Arc::clone(options)),
379            )?;
380            Ok(Some(options))
381        } else {
382            Ok(None)
383        }
384    }
385
386    fn get_headers(&mut self, req: Resource<Request>) -> wasmtime::Result<Resource<Headers>> {
387        let Request { headers, .. } = get_request(self.table, &req)?;
388        // `get-headers` promises immutable headers; that includes requests built with `Request::new`.
389        let mut headers = headers.clone();
390        headers.set_immutable();
391        push_fields(self.table, headers)
392    }
393}
394
395impl HostRequestOptions for WasiHttpCtxView<'_> {
396    fn new(&mut self) -> wasmtime::Result<Resource<RequestOptions>> {
397        push_request_options(self.table, RequestOptions::new_mutable_default())
398    }
399
400    fn get_connect_timeout(
401        &mut self,
402        opts: Resource<RequestOptions>,
403    ) -> wasmtime::Result<Option<Duration>> {
404        let opts = get_request_options(self.table, &opts)?;
405        let Some(connect_timeout) = opts.connect_timeout else {
406            return Ok(None);
407        };
408        let ns = connect_timeout.as_nanos();
409        let ns = Duration::try_from(ns)
410            .context("connect timeout duration nanoseconds do not fit in u64")?;
411        Ok(Some(ns))
412    }
413
414    fn set_connect_timeout(
415        &mut self,
416        opts: Resource<RequestOptions>,
417        duration: Option<Duration>,
418    ) -> RequestOptionsResult<()> {
419        let opts = get_request_options_mut(self.table, &opts)?;
420        let opts = opts.get_mut().ok_or(RequestOptionsError::Immutable)?;
421        opts.connect_timeout = duration.map(core::time::Duration::from_nanos);
422        Ok(())
423    }
424
425    fn get_first_byte_timeout(
426        &mut self,
427        opts: Resource<RequestOptions>,
428    ) -> wasmtime::Result<Option<Duration>> {
429        let opts = get_request_options(self.table, &opts)?;
430        let Some(first_byte_timeout) = opts.first_byte_timeout else {
431            return Ok(None);
432        };
433        let ns = first_byte_timeout.as_nanos();
434        let ns = Duration::try_from(ns)
435            .context("first byte timeout duration nanoseconds do not fit in u64")?;
436        Ok(Some(ns))
437    }
438
439    fn set_first_byte_timeout(
440        &mut self,
441        opts: Resource<RequestOptions>,
442        duration: Option<Duration>,
443    ) -> RequestOptionsResult<()> {
444        let opts = get_request_options_mut(self.table, &opts)?;
445        let opts = opts.get_mut().ok_or(RequestOptionsError::Immutable)?;
446        opts.first_byte_timeout = duration.map(core::time::Duration::from_nanos);
447        Ok(())
448    }
449
450    fn get_between_bytes_timeout(
451        &mut self,
452        opts: Resource<RequestOptions>,
453    ) -> wasmtime::Result<Option<Duration>> {
454        let opts = get_request_options(self.table, &opts)?;
455        let Some(between_bytes_timeout) = opts.between_bytes_timeout else {
456            return Ok(None);
457        };
458        let ns = between_bytes_timeout.as_nanos();
459        let ns = Duration::try_from(ns)
460            .context("between bytes timeout duration nanoseconds do not fit in u64")?;
461        Ok(Some(ns))
462    }
463
464    fn set_between_bytes_timeout(
465        &mut self,
466        opts: Resource<RequestOptions>,
467        duration: Option<Duration>,
468    ) -> RequestOptionsResult<()> {
469        let opts = get_request_options_mut(self.table, &opts)?;
470        let opts = opts.get_mut().ok_or(RequestOptionsError::Immutable)?;
471        opts.between_bytes_timeout = duration.map(core::time::Duration::from_nanos);
472        Ok(())
473    }
474
475    fn clone(
476        &mut self,
477        opts: Resource<RequestOptions>,
478    ) -> wasmtime::Result<Resource<RequestOptions>> {
479        let opts = get_request_options(self.table, &opts)?;
480        push_request_options(self.table, RequestOptions::new_mutable(Arc::clone(opts)))
481    }
482
483    fn drop(&mut self, opts: Resource<RequestOptions>) -> wasmtime::Result<()> {
484        delete_request_options(self.table, opts)?;
485        Ok(())
486    }
487}
488
489fn new_response<S>(
490    mut store: S,
491    mut getter: impl FnMut(&mut S::Data) -> WasiHttpCtxView<'_> + Copy + Send + 'static,
492    headers: Resource<Headers>,
493    contents: Option<StreamReader<u8>>,
494    trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
495) -> wasmtime::Result<(Resource<Response>, FutureReader<Result<(), ErrorCode>>)>
496where
497    S: AsContextMut,
498{
499    let mut store = store.as_context_mut();
500    let (body, body_result) = Body::new_guest(&mut store, getter, contents, trailers)?;
501    let cx = getter(store.data_mut());
502    let headers = delete_fields(cx.table, headers)?;
503    let res = Response {
504        status: http::StatusCode::OK,
505        headers,
506        body,
507    };
508    let res = cx.table.push(res)?;
509    Ok((res, body_result))
510}
511
512impl<T> HostResponseWithStore<T> for WasiHttp {
513    fn new(
514        store: Access<T, Self>,
515        headers: Resource<Headers>,
516        contents: Option<StreamReader<u8>>,
517        trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
518    ) -> wasmtime::Result<(Resource<Response>, FutureReader<Result<(), ErrorCode>>)> {
519        let getter = store.getter();
520        new_response(store, getter, headers, contents, trailers)
521    }
522
523    fn consume_body(
524        mut store: Access<T, Self>,
525        res: Resource<Response>,
526        fut: FutureReader<Result<(), ErrorCode>>,
527    ) -> wasmtime::Result<(
528        StreamReader<u8>,
529        FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
530    )> {
531        let getter = store.getter();
532        let Response { body, .. } = store.get().table.delete(res)?;
533        body.consume(store, fut, getter)
534    }
535
536    fn drop(mut store: Access<'_, T, Self>, res: Resource<Response>) -> wasmtime::Result<()> {
537        let Response { body, .. } = store.get().table.delete(res)?;
538        body.drop(store)?;
539        Ok(())
540    }
541}
542
543impl HostResponse for WasiHttpCtxView<'_> {
544    fn get_status_code(&mut self, res: Resource<Response>) -> wasmtime::Result<StatusCode> {
545        let res = get_response(self.table, &res)?;
546        Ok(res.status.into())
547    }
548
549    fn set_status_code(
550        &mut self,
551        res: Resource<Response>,
552        status_code: StatusCode,
553    ) -> wasmtime::Result<Result<(), ()>> {
554        let res = get_response_mut(self.table, &res)?;
555        match http::StatusCode::from_u16(status_code) {
556            Ok(status) if matches!(status_code, 100..=599) => {
557                res.status = status;
558                Ok(Ok(()))
559            }
560            _ => Ok(Err(())),
561        }
562    }
563
564    fn get_headers(&mut self, res: Resource<Response>) -> wasmtime::Result<Resource<Headers>> {
565        let Response { headers, .. } = get_response(self.table, &res)?;
566        // The response side makes the same promise as the request side.
567        let mut headers = headers.clone();
568        headers.set_immutable();
569        push_fields(self.table, headers)
570    }
571}
572
573impl Host for WasiHttpCtxView<'_> {
574    fn convert_error_code(&mut self, error: HttpError) -> wasmtime::Result<ErrorCode> {
575        error.downcast()
576    }
577
578    fn convert_header_error(
579        &mut self,
580        error: crate::p3::HeaderError,
581    ) -> wasmtime::Result<HeaderError> {
582        error.downcast()
583    }
584
585    fn convert_request_options_error(
586        &mut self,
587        error: crate::p3::RequestOptionsError,
588    ) -> wasmtime::Result<RequestOptionsError> {
589        error.downcast()
590    }
591}
592
593mod named {
594    use crate::p3::bindings::clocks::monotonic_clock::Duration;
595    use crate::p3::bindings::http::types::{
596        ErrorCode, FieldName, FieldValue, Fields, HeaderError, Headers, Method, Request,
597        RequestOptions, RequestOptionsError, Response, Scheme, StatusCode, Trailers,
598    };
599    use crate::p3::bindings::named_imports::wasi::http::types;
600    use crate::p3::{HeaderResult, HttpError, RequestOptionsResult};
601    use crate::{WasiHttpNamed, WasiHttpNamedView};
602    use wasmtime::component::{Access, FutureReader, Resource, StreamReader};
603    use wasmtime_wasi::{NamedId, WasiCtxNamedView};
604
605    impl<T> types::Host for WasiCtxNamedView<'_, T>
606    where
607        T: WasiHttpNamedView,
608    {
609        fn convert_error_code(&mut self, error: HttpError) -> wasmtime::Result<ErrorCode> {
610            error.downcast()
611        }
612
613        fn convert_header_error(
614            &mut self,
615            error: crate::p3::HeaderError,
616        ) -> wasmtime::Result<HeaderError> {
617            error.downcast()
618        }
619
620        fn convert_request_options_error(
621            &mut self,
622            error: crate::p3::RequestOptionsError,
623        ) -> wasmtime::Result<RequestOptionsError> {
624            error.downcast()
625        }
626    }
627
628    impl<T> types::HostFields for WasiCtxNamedView<'_, T>
629    where
630        T: WasiHttpNamedView,
631    {
632        fn new(&mut self, id: NamedId) -> wasmtime::Result<Resource<Fields>> {
633            super::HostFields::new(&mut self.0.http(id))
634        }
635
636        fn from_list(
637            &mut self,
638            id: NamedId,
639            entries: Vec<(FieldName, FieldValue)>,
640        ) -> HeaderResult<Resource<Fields>> {
641            super::HostFields::from_list(&mut self.0.http(id), entries)
642        }
643
644        fn get(
645            &mut self,
646            id: NamedId,
647            fields: Resource<Fields>,
648            name: FieldName,
649        ) -> wasmtime::Result<Vec<FieldValue>> {
650            super::HostFields::get(&mut self.0.http(id), fields, name)
651        }
652
653        fn has(
654            &mut self,
655            id: NamedId,
656            fields: Resource<Fields>,
657            name: FieldName,
658        ) -> wasmtime::Result<bool> {
659            super::HostFields::has(&mut self.0.http(id), fields, name)
660        }
661
662        fn set(
663            &mut self,
664            id: NamedId,
665            fields: Resource<Fields>,
666            name: FieldName,
667            values: Vec<FieldValue>,
668        ) -> HeaderResult<()> {
669            super::HostFields::set(&mut self.0.http(id), fields, name, values)
670        }
671
672        fn delete(
673            &mut self,
674            id: NamedId,
675            fields: Resource<Fields>,
676            name: FieldName,
677        ) -> HeaderResult<()> {
678            super::HostFields::delete(&mut self.0.http(id), fields, name)
679        }
680
681        fn get_and_delete(
682            &mut self,
683            id: NamedId,
684            fields: Resource<Fields>,
685            name: FieldName,
686        ) -> HeaderResult<Vec<FieldValue>> {
687            super::HostFields::get_and_delete(&mut self.0.http(id), fields, name)
688        }
689
690        fn append(
691            &mut self,
692            id: NamedId,
693            fields: Resource<Fields>,
694            name: FieldName,
695            value: FieldValue,
696        ) -> HeaderResult<()> {
697            super::HostFields::append(&mut self.0.http(id), fields, name, value)
698        }
699
700        fn copy_all(
701            &mut self,
702            id: NamedId,
703            fields: Resource<Fields>,
704        ) -> wasmtime::Result<Vec<(FieldName, FieldValue)>> {
705            super::HostFields::copy_all(&mut self.0.http(id), fields)
706        }
707
708        fn clone(
709            &mut self,
710            id: NamedId,
711            fields: Resource<Fields>,
712        ) -> wasmtime::Result<Resource<Fields>> {
713            super::HostFields::clone(&mut self.0.http(id), fields)
714        }
715
716        fn drop(&mut self, id: NamedId, fields: Resource<Fields>) -> wasmtime::Result<()> {
717            super::HostFields::drop(&mut self.0.http(id), fields)
718        }
719    }
720
721    impl<T> types::HostRequest for WasiCtxNamedView<'_, T>
722    where
723        T: WasiHttpNamedView,
724    {
725        fn get_method(&mut self, id: NamedId, req: Resource<Request>) -> wasmtime::Result<Method> {
726            super::HostRequest::get_method(&mut self.0.http(id), req)
727        }
728
729        fn set_method(
730            &mut self,
731            id: NamedId,
732            req: Resource<Request>,
733            method: Method,
734        ) -> wasmtime::Result<Result<(), ()>> {
735            super::HostRequest::set_method(&mut self.0.http(id), req, method)
736        }
737
738        fn get_path_with_query(
739            &mut self,
740            id: NamedId,
741            req: Resource<Request>,
742        ) -> wasmtime::Result<Option<String>> {
743            super::HostRequest::get_path_with_query(&mut self.0.http(id), req)
744        }
745
746        fn set_path_with_query(
747            &mut self,
748            id: NamedId,
749            req: Resource<Request>,
750            path_with_query: Option<String>,
751        ) -> wasmtime::Result<Result<(), ()>> {
752            super::HostRequest::set_path_with_query(&mut self.0.http(id), req, path_with_query)
753        }
754
755        fn get_scheme(
756            &mut self,
757            id: NamedId,
758            req: Resource<Request>,
759        ) -> wasmtime::Result<Option<Scheme>> {
760            super::HostRequest::get_scheme(&mut self.0.http(id), req)
761        }
762
763        fn set_scheme(
764            &mut self,
765            id: NamedId,
766            req: Resource<Request>,
767            scheme: Option<Scheme>,
768        ) -> wasmtime::Result<Result<(), ()>> {
769            super::HostRequest::set_scheme(&mut self.0.http(id), req, scheme)
770        }
771
772        fn get_authority(
773            &mut self,
774            id: NamedId,
775            req: Resource<Request>,
776        ) -> wasmtime::Result<Option<String>> {
777            super::HostRequest::get_authority(&mut self.0.http(id), req)
778        }
779
780        fn set_authority(
781            &mut self,
782            id: NamedId,
783            req: Resource<Request>,
784            authority: Option<String>,
785        ) -> wasmtime::Result<Result<(), ()>> {
786            super::HostRequest::set_authority(&mut self.0.http(id), req, authority)
787        }
788
789        fn get_options(
790            &mut self,
791            id: NamedId,
792            req: Resource<Request>,
793        ) -> wasmtime::Result<Option<Resource<RequestOptions>>> {
794            super::HostRequest::get_options(&mut self.0.http(id), req)
795        }
796
797        fn get_headers(
798            &mut self,
799            id: NamedId,
800            req: Resource<Request>,
801        ) -> wasmtime::Result<Resource<Headers>> {
802            super::HostRequest::get_headers(&mut self.0.http(id), req)
803        }
804    }
805
806    impl<T> types::HostRequestOptions for WasiCtxNamedView<'_, T>
807    where
808        T: WasiHttpNamedView,
809    {
810        fn new(&mut self, id: NamedId) -> wasmtime::Result<Resource<RequestOptions>> {
811            super::HostRequestOptions::new(&mut self.0.http(id))
812        }
813
814        fn get_connect_timeout(
815            &mut self,
816            id: NamedId,
817            opts: Resource<RequestOptions>,
818        ) -> wasmtime::Result<Option<Duration>> {
819            super::HostRequestOptions::get_connect_timeout(&mut self.0.http(id), opts)
820        }
821
822        fn set_connect_timeout(
823            &mut self,
824            id: NamedId,
825            opts: Resource<RequestOptions>,
826            duration: Option<Duration>,
827        ) -> RequestOptionsResult<()> {
828            super::HostRequestOptions::set_connect_timeout(&mut self.0.http(id), opts, duration)
829        }
830
831        fn get_first_byte_timeout(
832            &mut self,
833            id: NamedId,
834            opts: Resource<RequestOptions>,
835        ) -> wasmtime::Result<Option<Duration>> {
836            super::HostRequestOptions::get_first_byte_timeout(&mut self.0.http(id), opts)
837        }
838
839        fn set_first_byte_timeout(
840            &mut self,
841            id: NamedId,
842            opts: Resource<RequestOptions>,
843            duration: Option<Duration>,
844        ) -> RequestOptionsResult<()> {
845            super::HostRequestOptions::set_first_byte_timeout(&mut self.0.http(id), opts, duration)
846        }
847
848        fn get_between_bytes_timeout(
849            &mut self,
850            id: NamedId,
851            opts: Resource<RequestOptions>,
852        ) -> wasmtime::Result<Option<Duration>> {
853            super::HostRequestOptions::get_between_bytes_timeout(&mut self.0.http(id), opts)
854        }
855
856        fn set_between_bytes_timeout(
857            &mut self,
858            id: NamedId,
859            opts: Resource<RequestOptions>,
860            duration: Option<Duration>,
861        ) -> RequestOptionsResult<()> {
862            super::HostRequestOptions::set_between_bytes_timeout(
863                &mut self.0.http(id),
864                opts,
865                duration,
866            )
867        }
868
869        fn clone(
870            &mut self,
871            id: NamedId,
872            opts: Resource<RequestOptions>,
873        ) -> wasmtime::Result<Resource<RequestOptions>> {
874            super::HostRequestOptions::clone(&mut self.0.http(id), opts)
875        }
876
877        fn drop(&mut self, id: NamedId, opts: Resource<RequestOptions>) -> wasmtime::Result<()> {
878            super::HostRequestOptions::drop(&mut self.0.http(id), opts)
879        }
880    }
881
882    impl<T> types::HostResponse for WasiCtxNamedView<'_, T>
883    where
884        T: WasiHttpNamedView,
885    {
886        fn get_status_code(
887            &mut self,
888            id: NamedId,
889            res: Resource<Response>,
890        ) -> wasmtime::Result<StatusCode> {
891            super::HostResponse::get_status_code(&mut self.0.http(id), res)
892        }
893
894        fn set_status_code(
895            &mut self,
896            id: NamedId,
897            res: Resource<Response>,
898            status_code: StatusCode,
899        ) -> wasmtime::Result<Result<(), ()>> {
900            super::HostResponse::set_status_code(&mut self.0.http(id), res, status_code)
901        }
902
903        fn get_headers(
904            &mut self,
905            id: NamedId,
906            res: Resource<Response>,
907        ) -> wasmtime::Result<Resource<Headers>> {
908            super::HostResponse::get_headers(&mut self.0.http(id), res)
909        }
910    }
911
912    impl<T, U> types::HostRequestWithStore<U> for WasiHttpNamed<T>
913    where
914        T: WasiHttpNamedView,
915        U: 'static,
916    {
917        fn new(
918            store: Access<U, Self>,
919            id: NamedId,
920            headers: Resource<Headers>,
921            contents: Option<StreamReader<u8>>,
922            trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
923            options: Option<Resource<RequestOptions>>,
924        ) -> wasmtime::Result<(Resource<Request>, FutureReader<Result<(), ErrorCode>>)> {
925            let getter = store.getter();
926            super::new_request(
927                store,
928                move |data| getter(data).0.http(id),
929                headers,
930                contents,
931                trailers,
932                options,
933            )
934        }
935
936        fn consume_body(
937            mut store: Access<U, Self>,
938            id: NamedId,
939            req: Resource<Request>,
940            fut: FutureReader<Result<(), ErrorCode>>,
941        ) -> wasmtime::Result<(
942            StreamReader<u8>,
943            FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
944        )> {
945            let getter = store.getter();
946            let Request { body, .. } = store.get().0.http(id).table.delete(req)?;
947            body.consume(store, fut, move |data: &mut U| getter(data).0.http(id))
948        }
949
950        fn drop(
951            mut store: Access<'_, U, Self>,
952            id: NamedId,
953            req: Resource<Request>,
954        ) -> wasmtime::Result<()> {
955            let Request { body, .. } = store.get().0.http(id).table.delete(req)?;
956            body.drop(store)?;
957            Ok(())
958        }
959    }
960
961    impl<T, U> types::HostResponseWithStore<U> for WasiHttpNamed<T>
962    where
963        T: WasiHttpNamedView,
964        U: 'static,
965    {
966        fn new(
967            store: Access<U, Self>,
968            id: NamedId,
969            headers: Resource<Headers>,
970            contents: Option<StreamReader<u8>>,
971            trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
972        ) -> wasmtime::Result<(Resource<Response>, FutureReader<Result<(), ErrorCode>>)> {
973            let getter = store.getter();
974            super::new_response(
975                store,
976                move |data| getter(data).0.http(id),
977                headers,
978                contents,
979                trailers,
980            )
981        }
982
983        fn consume_body(
984            mut store: Access<U, Self>,
985            id: NamedId,
986            res: Resource<Response>,
987            fut: FutureReader<Result<(), ErrorCode>>,
988        ) -> wasmtime::Result<(
989            StreamReader<u8>,
990            FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
991        )> {
992            let getter = store.getter();
993            let Response { body, .. } = store.get().0.http(id).table.delete(res)?;
994            body.consume(store, fut, move |data: &mut U| getter(data).0.http(id))
995        }
996
997        fn drop(
998            mut store: Access<'_, U, Self>,
999            id: NamedId,
1000            res: Resource<Response>,
1001        ) -> wasmtime::Result<()> {
1002            let Response { body, .. } = store.get().0.http(id).table.delete(res)?;
1003            body.drop(store)?;
1004            Ok(())
1005        }
1006    }
1007}