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        let Some(path_with_query) = path_with_query else {
315            req.path_with_query = None;
316            return Ok(Ok(()));
317        };
318        let Ok(path_with_query) = path_with_query.try_into() else {
319            return Ok(Err(()));
320        };
321        req.path_with_query = Some(path_with_query);
322        Ok(Ok(()))
323    }
324
325    fn get_scheme(&mut self, req: Resource<Request>) -> wasmtime::Result<Option<Scheme>> {
326        let Request { scheme, .. } = get_request(self.table, &req)?;
327        Ok(scheme.as_ref().map(Into::into))
328    }
329
330    fn set_scheme(
331        &mut self,
332        req: Resource<Request>,
333        scheme: Option<Scheme>,
334    ) -> wasmtime::Result<Result<(), ()>> {
335        let req = get_request_mut(self.table, &req)?;
336        let Some(scheme) = scheme else {
337            req.scheme = None;
338            return Ok(Ok(()));
339        };
340        let Ok(scheme) = scheme.try_into() else {
341            return Ok(Err(()));
342        };
343        req.scheme = Some(scheme);
344        Ok(Ok(()))
345    }
346
347    fn get_authority(&mut self, req: Resource<Request>) -> wasmtime::Result<Option<String>> {
348        let Request { authority, .. } = get_request(self.table, &req)?;
349        Ok(authority.as_ref().map(|auth| auth.as_str().into()))
350    }
351
352    fn set_authority(
353        &mut self,
354        req: Resource<Request>,
355        authority: Option<String>,
356    ) -> wasmtime::Result<Result<(), ()>> {
357        let req = get_request_mut(self.table, &req)?;
358        let Some(authority) = authority else {
359            req.authority = None;
360            return Ok(Ok(()));
361        };
362        let Ok(authority) = crate::parse_authority(authority) else {
363            return Ok(Err(()));
364        };
365        req.authority = Some(authority);
366        Ok(Ok(()))
367    }
368
369    fn get_options(
370        &mut self,
371        req: Resource<Request>,
372    ) -> wasmtime::Result<Option<Resource<RequestOptions>>> {
373        let Request { options, .. } = get_request(self.table, &req)?;
374        if let Some(options) = options {
375            let options = push_request_options(
376                self.table,
377                RequestOptions::new_immutable(Arc::clone(options)),
378            )?;
379            Ok(Some(options))
380        } else {
381            Ok(None)
382        }
383    }
384
385    fn get_headers(&mut self, req: Resource<Request>) -> wasmtime::Result<Resource<Headers>> {
386        let Request { headers, .. } = get_request(self.table, &req)?;
387        push_fields(self.table, headers.clone())
388    }
389}
390
391impl HostRequestOptions for WasiHttpCtxView<'_> {
392    fn new(&mut self) -> wasmtime::Result<Resource<RequestOptions>> {
393        push_request_options(self.table, RequestOptions::new_mutable_default())
394    }
395
396    fn get_connect_timeout(
397        &mut self,
398        opts: Resource<RequestOptions>,
399    ) -> wasmtime::Result<Option<Duration>> {
400        let opts = get_request_options(self.table, &opts)?;
401        let Some(connect_timeout) = opts.connect_timeout else {
402            return Ok(None);
403        };
404        let ns = connect_timeout.as_nanos();
405        let ns = Duration::try_from(ns)
406            .context("connect timeout duration nanoseconds do not fit in u64")?;
407        Ok(Some(ns))
408    }
409
410    fn set_connect_timeout(
411        &mut self,
412        opts: Resource<RequestOptions>,
413        duration: Option<Duration>,
414    ) -> RequestOptionsResult<()> {
415        let opts = get_request_options_mut(self.table, &opts)?;
416        let opts = opts.get_mut().ok_or(RequestOptionsError::Immutable)?;
417        opts.connect_timeout = duration.map(core::time::Duration::from_nanos);
418        Ok(())
419    }
420
421    fn get_first_byte_timeout(
422        &mut self,
423        opts: Resource<RequestOptions>,
424    ) -> wasmtime::Result<Option<Duration>> {
425        let opts = get_request_options(self.table, &opts)?;
426        let Some(first_byte_timeout) = opts.first_byte_timeout else {
427            return Ok(None);
428        };
429        let ns = first_byte_timeout.as_nanos();
430        let ns = Duration::try_from(ns)
431            .context("first byte timeout duration nanoseconds do not fit in u64")?;
432        Ok(Some(ns))
433    }
434
435    fn set_first_byte_timeout(
436        &mut self,
437        opts: Resource<RequestOptions>,
438        duration: Option<Duration>,
439    ) -> RequestOptionsResult<()> {
440        let opts = get_request_options_mut(self.table, &opts)?;
441        let opts = opts.get_mut().ok_or(RequestOptionsError::Immutable)?;
442        opts.first_byte_timeout = duration.map(core::time::Duration::from_nanos);
443        Ok(())
444    }
445
446    fn get_between_bytes_timeout(
447        &mut self,
448        opts: Resource<RequestOptions>,
449    ) -> wasmtime::Result<Option<Duration>> {
450        let opts = get_request_options(self.table, &opts)?;
451        let Some(between_bytes_timeout) = opts.between_bytes_timeout else {
452            return Ok(None);
453        };
454        let ns = between_bytes_timeout.as_nanos();
455        let ns = Duration::try_from(ns)
456            .context("between bytes timeout duration nanoseconds do not fit in u64")?;
457        Ok(Some(ns))
458    }
459
460    fn set_between_bytes_timeout(
461        &mut self,
462        opts: Resource<RequestOptions>,
463        duration: Option<Duration>,
464    ) -> RequestOptionsResult<()> {
465        let opts = get_request_options_mut(self.table, &opts)?;
466        let opts = opts.get_mut().ok_or(RequestOptionsError::Immutable)?;
467        opts.between_bytes_timeout = duration.map(core::time::Duration::from_nanos);
468        Ok(())
469    }
470
471    fn clone(
472        &mut self,
473        opts: Resource<RequestOptions>,
474    ) -> wasmtime::Result<Resource<RequestOptions>> {
475        let opts = get_request_options(self.table, &opts)?;
476        push_request_options(self.table, RequestOptions::new_mutable(Arc::clone(opts)))
477    }
478
479    fn drop(&mut self, opts: Resource<RequestOptions>) -> wasmtime::Result<()> {
480        delete_request_options(self.table, opts)?;
481        Ok(())
482    }
483}
484
485fn new_response<S>(
486    mut store: S,
487    mut getter: impl FnMut(&mut S::Data) -> WasiHttpCtxView<'_> + Copy + Send + 'static,
488    headers: Resource<Headers>,
489    contents: Option<StreamReader<u8>>,
490    trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
491) -> wasmtime::Result<(Resource<Response>, FutureReader<Result<(), ErrorCode>>)>
492where
493    S: AsContextMut,
494{
495    let mut store = store.as_context_mut();
496    let (body, body_result) = Body::new_guest(&mut store, getter, contents, trailers)?;
497    let cx = getter(store.data_mut());
498    let headers = delete_fields(cx.table, headers)?;
499    let res = Response {
500        status: http::StatusCode::OK,
501        headers,
502        body,
503    };
504    let res = cx.table.push(res)?;
505    Ok((res, body_result))
506}
507
508impl<T> HostResponseWithStore<T> for WasiHttp {
509    fn new(
510        store: Access<T, Self>,
511        headers: Resource<Headers>,
512        contents: Option<StreamReader<u8>>,
513        trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
514    ) -> wasmtime::Result<(Resource<Response>, FutureReader<Result<(), ErrorCode>>)> {
515        let getter = store.getter();
516        new_response(store, getter, headers, contents, trailers)
517    }
518
519    fn consume_body(
520        mut store: Access<T, Self>,
521        res: Resource<Response>,
522        fut: FutureReader<Result<(), ErrorCode>>,
523    ) -> wasmtime::Result<(
524        StreamReader<u8>,
525        FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
526    )> {
527        let getter = store.getter();
528        let Response { body, .. } = store.get().table.delete(res)?;
529        body.consume(store, fut, getter)
530    }
531
532    fn drop(mut store: Access<'_, T, Self>, res: Resource<Response>) -> wasmtime::Result<()> {
533        let Response { body, .. } = store.get().table.delete(res)?;
534        body.drop(store)?;
535        Ok(())
536    }
537}
538
539impl HostResponse for WasiHttpCtxView<'_> {
540    fn get_status_code(&mut self, res: Resource<Response>) -> wasmtime::Result<StatusCode> {
541        let res = get_response(self.table, &res)?;
542        Ok(res.status.into())
543    }
544
545    fn set_status_code(
546        &mut self,
547        res: Resource<Response>,
548        status_code: StatusCode,
549    ) -> wasmtime::Result<Result<(), ()>> {
550        let res = get_response_mut(self.table, &res)?;
551        match http::StatusCode::from_u16(status_code) {
552            Ok(status) if matches!(status_code, 100..=599) => {
553                res.status = status;
554                Ok(Ok(()))
555            }
556            _ => Ok(Err(())),
557        }
558    }
559
560    fn get_headers(&mut self, res: Resource<Response>) -> wasmtime::Result<Resource<Headers>> {
561        let Response { headers, .. } = get_response(self.table, &res)?;
562        push_fields(self.table, headers.clone())
563    }
564}
565
566impl Host for WasiHttpCtxView<'_> {
567    fn convert_error_code(&mut self, error: HttpError) -> wasmtime::Result<ErrorCode> {
568        error.downcast()
569    }
570
571    fn convert_header_error(
572        &mut self,
573        error: crate::p3::HeaderError,
574    ) -> wasmtime::Result<HeaderError> {
575        error.downcast()
576    }
577
578    fn convert_request_options_error(
579        &mut self,
580        error: crate::p3::RequestOptionsError,
581    ) -> wasmtime::Result<RequestOptionsError> {
582        error.downcast()
583    }
584}
585
586mod named {
587    use crate::p3::bindings::clocks::monotonic_clock::Duration;
588    use crate::p3::bindings::http::types::{
589        ErrorCode, FieldName, FieldValue, Fields, HeaderError, Headers, Method, Request,
590        RequestOptions, RequestOptionsError, Response, Scheme, StatusCode, Trailers,
591    };
592    use crate::p3::bindings::named_imports::wasi::http::types;
593    use crate::p3::{HeaderResult, HttpError, RequestOptionsResult};
594    use crate::{WasiHttpNamed, WasiHttpNamedView};
595    use wasmtime::component::{Access, FutureReader, Resource, StreamReader};
596    use wasmtime_wasi::{NamedId, WasiCtxNamedView};
597
598    impl<T> types::Host for WasiCtxNamedView<'_, T>
599    where
600        T: WasiHttpNamedView,
601    {
602        fn convert_error_code(&mut self, error: HttpError) -> wasmtime::Result<ErrorCode> {
603            error.downcast()
604        }
605
606        fn convert_header_error(
607            &mut self,
608            error: crate::p3::HeaderError,
609        ) -> wasmtime::Result<HeaderError> {
610            error.downcast()
611        }
612
613        fn convert_request_options_error(
614            &mut self,
615            error: crate::p3::RequestOptionsError,
616        ) -> wasmtime::Result<RequestOptionsError> {
617            error.downcast()
618        }
619    }
620
621    impl<T> types::HostFields for WasiCtxNamedView<'_, T>
622    where
623        T: WasiHttpNamedView,
624    {
625        fn new(&mut self, id: NamedId) -> wasmtime::Result<Resource<Fields>> {
626            super::HostFields::new(&mut self.0.http(id))
627        }
628
629        fn from_list(
630            &mut self,
631            id: NamedId,
632            entries: Vec<(FieldName, FieldValue)>,
633        ) -> HeaderResult<Resource<Fields>> {
634            super::HostFields::from_list(&mut self.0.http(id), entries)
635        }
636
637        fn get(
638            &mut self,
639            id: NamedId,
640            fields: Resource<Fields>,
641            name: FieldName,
642        ) -> wasmtime::Result<Vec<FieldValue>> {
643            super::HostFields::get(&mut self.0.http(id), fields, name)
644        }
645
646        fn has(
647            &mut self,
648            id: NamedId,
649            fields: Resource<Fields>,
650            name: FieldName,
651        ) -> wasmtime::Result<bool> {
652            super::HostFields::has(&mut self.0.http(id), fields, name)
653        }
654
655        fn set(
656            &mut self,
657            id: NamedId,
658            fields: Resource<Fields>,
659            name: FieldName,
660            values: Vec<FieldValue>,
661        ) -> HeaderResult<()> {
662            super::HostFields::set(&mut self.0.http(id), fields, name, values)
663        }
664
665        fn delete(
666            &mut self,
667            id: NamedId,
668            fields: Resource<Fields>,
669            name: FieldName,
670        ) -> HeaderResult<()> {
671            super::HostFields::delete(&mut self.0.http(id), fields, name)
672        }
673
674        fn get_and_delete(
675            &mut self,
676            id: NamedId,
677            fields: Resource<Fields>,
678            name: FieldName,
679        ) -> HeaderResult<Vec<FieldValue>> {
680            super::HostFields::get_and_delete(&mut self.0.http(id), fields, name)
681        }
682
683        fn append(
684            &mut self,
685            id: NamedId,
686            fields: Resource<Fields>,
687            name: FieldName,
688            value: FieldValue,
689        ) -> HeaderResult<()> {
690            super::HostFields::append(&mut self.0.http(id), fields, name, value)
691        }
692
693        fn copy_all(
694            &mut self,
695            id: NamedId,
696            fields: Resource<Fields>,
697        ) -> wasmtime::Result<Vec<(FieldName, FieldValue)>> {
698            super::HostFields::copy_all(&mut self.0.http(id), fields)
699        }
700
701        fn clone(
702            &mut self,
703            id: NamedId,
704            fields: Resource<Fields>,
705        ) -> wasmtime::Result<Resource<Fields>> {
706            super::HostFields::clone(&mut self.0.http(id), fields)
707        }
708
709        fn drop(&mut self, id: NamedId, fields: Resource<Fields>) -> wasmtime::Result<()> {
710            super::HostFields::drop(&mut self.0.http(id), fields)
711        }
712    }
713
714    impl<T> types::HostRequest for WasiCtxNamedView<'_, T>
715    where
716        T: WasiHttpNamedView,
717    {
718        fn get_method(&mut self, id: NamedId, req: Resource<Request>) -> wasmtime::Result<Method> {
719            super::HostRequest::get_method(&mut self.0.http(id), req)
720        }
721
722        fn set_method(
723            &mut self,
724            id: NamedId,
725            req: Resource<Request>,
726            method: Method,
727        ) -> wasmtime::Result<Result<(), ()>> {
728            super::HostRequest::set_method(&mut self.0.http(id), req, method)
729        }
730
731        fn get_path_with_query(
732            &mut self,
733            id: NamedId,
734            req: Resource<Request>,
735        ) -> wasmtime::Result<Option<String>> {
736            super::HostRequest::get_path_with_query(&mut self.0.http(id), req)
737        }
738
739        fn set_path_with_query(
740            &mut self,
741            id: NamedId,
742            req: Resource<Request>,
743            path_with_query: Option<String>,
744        ) -> wasmtime::Result<Result<(), ()>> {
745            super::HostRequest::set_path_with_query(&mut self.0.http(id), req, path_with_query)
746        }
747
748        fn get_scheme(
749            &mut self,
750            id: NamedId,
751            req: Resource<Request>,
752        ) -> wasmtime::Result<Option<Scheme>> {
753            super::HostRequest::get_scheme(&mut self.0.http(id), req)
754        }
755
756        fn set_scheme(
757            &mut self,
758            id: NamedId,
759            req: Resource<Request>,
760            scheme: Option<Scheme>,
761        ) -> wasmtime::Result<Result<(), ()>> {
762            super::HostRequest::set_scheme(&mut self.0.http(id), req, scheme)
763        }
764
765        fn get_authority(
766            &mut self,
767            id: NamedId,
768            req: Resource<Request>,
769        ) -> wasmtime::Result<Option<String>> {
770            super::HostRequest::get_authority(&mut self.0.http(id), req)
771        }
772
773        fn set_authority(
774            &mut self,
775            id: NamedId,
776            req: Resource<Request>,
777            authority: Option<String>,
778        ) -> wasmtime::Result<Result<(), ()>> {
779            super::HostRequest::set_authority(&mut self.0.http(id), req, authority)
780        }
781
782        fn get_options(
783            &mut self,
784            id: NamedId,
785            req: Resource<Request>,
786        ) -> wasmtime::Result<Option<Resource<RequestOptions>>> {
787            super::HostRequest::get_options(&mut self.0.http(id), req)
788        }
789
790        fn get_headers(
791            &mut self,
792            id: NamedId,
793            req: Resource<Request>,
794        ) -> wasmtime::Result<Resource<Headers>> {
795            super::HostRequest::get_headers(&mut self.0.http(id), req)
796        }
797    }
798
799    impl<T> types::HostRequestOptions for WasiCtxNamedView<'_, T>
800    where
801        T: WasiHttpNamedView,
802    {
803        fn new(&mut self, id: NamedId) -> wasmtime::Result<Resource<RequestOptions>> {
804            super::HostRequestOptions::new(&mut self.0.http(id))
805        }
806
807        fn get_connect_timeout(
808            &mut self,
809            id: NamedId,
810            opts: Resource<RequestOptions>,
811        ) -> wasmtime::Result<Option<Duration>> {
812            super::HostRequestOptions::get_connect_timeout(&mut self.0.http(id), opts)
813        }
814
815        fn set_connect_timeout(
816            &mut self,
817            id: NamedId,
818            opts: Resource<RequestOptions>,
819            duration: Option<Duration>,
820        ) -> RequestOptionsResult<()> {
821            super::HostRequestOptions::set_connect_timeout(&mut self.0.http(id), opts, duration)
822        }
823
824        fn get_first_byte_timeout(
825            &mut self,
826            id: NamedId,
827            opts: Resource<RequestOptions>,
828        ) -> wasmtime::Result<Option<Duration>> {
829            super::HostRequestOptions::get_first_byte_timeout(&mut self.0.http(id), opts)
830        }
831
832        fn set_first_byte_timeout(
833            &mut self,
834            id: NamedId,
835            opts: Resource<RequestOptions>,
836            duration: Option<Duration>,
837        ) -> RequestOptionsResult<()> {
838            super::HostRequestOptions::set_first_byte_timeout(&mut self.0.http(id), opts, duration)
839        }
840
841        fn get_between_bytes_timeout(
842            &mut self,
843            id: NamedId,
844            opts: Resource<RequestOptions>,
845        ) -> wasmtime::Result<Option<Duration>> {
846            super::HostRequestOptions::get_between_bytes_timeout(&mut self.0.http(id), opts)
847        }
848
849        fn set_between_bytes_timeout(
850            &mut self,
851            id: NamedId,
852            opts: Resource<RequestOptions>,
853            duration: Option<Duration>,
854        ) -> RequestOptionsResult<()> {
855            super::HostRequestOptions::set_between_bytes_timeout(
856                &mut self.0.http(id),
857                opts,
858                duration,
859            )
860        }
861
862        fn clone(
863            &mut self,
864            id: NamedId,
865            opts: Resource<RequestOptions>,
866        ) -> wasmtime::Result<Resource<RequestOptions>> {
867            super::HostRequestOptions::clone(&mut self.0.http(id), opts)
868        }
869
870        fn drop(&mut self, id: NamedId, opts: Resource<RequestOptions>) -> wasmtime::Result<()> {
871            super::HostRequestOptions::drop(&mut self.0.http(id), opts)
872        }
873    }
874
875    impl<T> types::HostResponse for WasiCtxNamedView<'_, T>
876    where
877        T: WasiHttpNamedView,
878    {
879        fn get_status_code(
880            &mut self,
881            id: NamedId,
882            res: Resource<Response>,
883        ) -> wasmtime::Result<StatusCode> {
884            super::HostResponse::get_status_code(&mut self.0.http(id), res)
885        }
886
887        fn set_status_code(
888            &mut self,
889            id: NamedId,
890            res: Resource<Response>,
891            status_code: StatusCode,
892        ) -> wasmtime::Result<Result<(), ()>> {
893            super::HostResponse::set_status_code(&mut self.0.http(id), res, status_code)
894        }
895
896        fn get_headers(
897            &mut self,
898            id: NamedId,
899            res: Resource<Response>,
900        ) -> wasmtime::Result<Resource<Headers>> {
901            super::HostResponse::get_headers(&mut self.0.http(id), res)
902        }
903    }
904
905    impl<T, U> types::HostRequestWithStore<U> for WasiHttpNamed<T>
906    where
907        T: WasiHttpNamedView,
908        U: 'static,
909    {
910        fn new(
911            store: Access<U, Self>,
912            id: NamedId,
913            headers: Resource<Headers>,
914            contents: Option<StreamReader<u8>>,
915            trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
916            options: Option<Resource<RequestOptions>>,
917        ) -> wasmtime::Result<(Resource<Request>, FutureReader<Result<(), ErrorCode>>)> {
918            let getter = store.getter();
919            super::new_request(
920                store,
921                move |data| getter(data).0.http(id),
922                headers,
923                contents,
924                trailers,
925                options,
926            )
927        }
928
929        fn consume_body(
930            mut store: Access<U, Self>,
931            id: NamedId,
932            req: Resource<Request>,
933            fut: FutureReader<Result<(), ErrorCode>>,
934        ) -> wasmtime::Result<(
935            StreamReader<u8>,
936            FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
937        )> {
938            let getter = store.getter();
939            let Request { body, .. } = store.get().0.http(id).table.delete(req)?;
940            body.consume(store, fut, move |data: &mut U| getter(data).0.http(id))
941        }
942
943        fn drop(
944            mut store: Access<'_, U, Self>,
945            id: NamedId,
946            req: Resource<Request>,
947        ) -> wasmtime::Result<()> {
948            let Request { body, .. } = store.get().0.http(id).table.delete(req)?;
949            body.drop(store)?;
950            Ok(())
951        }
952    }
953
954    impl<T, U> types::HostResponseWithStore<U> for WasiHttpNamed<T>
955    where
956        T: WasiHttpNamedView,
957        U: 'static,
958    {
959        fn new(
960            store: Access<U, Self>,
961            id: NamedId,
962            headers: Resource<Headers>,
963            contents: Option<StreamReader<u8>>,
964            trailers: FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
965        ) -> wasmtime::Result<(Resource<Response>, FutureReader<Result<(), ErrorCode>>)> {
966            let getter = store.getter();
967            super::new_response(
968                store,
969                move |data| getter(data).0.http(id),
970                headers,
971                contents,
972                trailers,
973            )
974        }
975
976        fn consume_body(
977            mut store: Access<U, Self>,
978            id: NamedId,
979            res: Resource<Response>,
980            fut: FutureReader<Result<(), ErrorCode>>,
981        ) -> wasmtime::Result<(
982            StreamReader<u8>,
983            FutureReader<Result<Option<Resource<Trailers>>, ErrorCode>>,
984        )> {
985            let getter = store.getter();
986            let Response { body, .. } = store.get().0.http(id).table.delete(res)?;
987            body.consume(store, fut, move |data: &mut U| getter(data).0.http(id))
988        }
989
990        fn drop(
991            mut store: Access<'_, U, Self>,
992            id: NamedId,
993            res: Resource<Response>,
994        ) -> wasmtime::Result<()> {
995            let Response { body, .. } = store.get().0.http(id).table.delete(res)?;
996            body.drop(store)?;
997            Ok(())
998        }
999    }
1000}