1use crate::p2::bindings::http::types::{self, Method, Scheme, StatusCode, Trailers};
4use crate::p2::body::{HostFutureTrailers, HostIncomingBody, HostOutgoingBody, StreamContext};
5use crate::p2::types::{
6 HostFutureIncomingResponse, HostIncomingRequest, HostIncomingResponse, HostOutgoingRequest,
7 HostOutgoingResponse, HostResponseOutparam,
8};
9use crate::p2::{HeaderError, HeaderResult, HttpError, HttpResult};
10use crate::{FieldMap, WasiHttpCtxView, get_content_length};
11use http::HeaderName;
12use std::str::FromStr;
13use wasmtime::component::Resource;
14use wasmtime::{error::Context as _, format_err};
15use wasmtime_wasi::p2::{DynInputStream, DynOutputStream, DynPollable};
16
17impl types::Host for WasiHttpCtxView<'_> {
18 fn convert_error_code(&mut self, err: HttpError) -> wasmtime::Result<types::ErrorCode> {
19 err.downcast()
20 }
21
22 fn convert_header_error(&mut self, err: HeaderError) -> wasmtime::Result<types::HeaderError> {
23 err.downcast()
24 }
25
26 fn http_error_code(
27 &mut self,
28 err: wasmtime::component::Resource<types::IoError>,
29 ) -> wasmtime::Result<Option<types::ErrorCode>> {
30 let e = self.table.get(&err)?;
31 Ok(e.downcast_ref::<types::ErrorCode>().cloned())
32 }
33}
34
35impl types::HostFields for WasiHttpCtxView<'_> {
36 fn new(&mut self) -> wasmtime::Result<Resource<FieldMap>> {
37 let limit = self.ctx.field_size_limit;
38 let id = self
39 .table
40 .push(FieldMap::new_mutable(limit))
41 .context("[new_fields] pushing fields")?;
42
43 Ok(id)
44 }
45
46 fn from_list(&mut self, entries: Vec<(String, Vec<u8>)>) -> HeaderResult<Resource<FieldMap>> {
47 let mut fields = FieldMap::new_mutable(self.ctx.field_size_limit);
48
49 for (header, value) in entries {
50 fields.append(self.hooks, header, value)?;
51 }
52
53 Ok(self.table.push(fields)?)
54 }
55
56 fn drop(&mut self, fields: Resource<FieldMap>) -> wasmtime::Result<()> {
57 self.table
58 .delete(fields)
59 .context("[drop_fields] deleting fields")?;
60 Ok(())
61 }
62
63 fn get(&mut self, fields: Resource<FieldMap>, name: String) -> wasmtime::Result<Vec<Vec<u8>>> {
64 let fields = self.table.get(&fields)?;
65
66 let header = match HeaderName::from_bytes(name.as_bytes()) {
67 Ok(header) => header,
68 Err(_) => return Ok(vec![]),
69 };
70
71 if !fields.contains_key(&header) {
72 return Ok(vec![]);
73 }
74
75 let res = fields
76 .get_all(&header)
77 .into_iter()
78 .map(|val| val.as_bytes().to_owned())
79 .collect();
80 Ok(res)
81 }
82
83 fn has(&mut self, fields: Resource<FieldMap>, name: String) -> wasmtime::Result<bool> {
84 let fields = self.table.get(&fields)?;
85
86 match HeaderName::from_bytes(name.as_bytes()) {
87 Ok(header) => Ok(fields.contains_key(&header)),
88 Err(_) => Ok(false),
89 }
90 }
91
92 fn set(
93 &mut self,
94 fields: Resource<FieldMap>,
95 name: String,
96 values: Vec<Vec<u8>>,
97 ) -> HeaderResult<()> {
98 let fields = self.table.get_mut(&fields)?;
99 fields.set(self.hooks, name, values)?;
100 Ok(())
101 }
102
103 fn delete(&mut self, fields: Resource<FieldMap>, name: String) -> HeaderResult<()> {
104 let fields = self.table.get_mut(&fields)?;
105 fields.remove_all(self.hooks, name)?;
106 Ok(())
107 }
108
109 fn append(
110 &mut self,
111 fields: Resource<FieldMap>,
112 name: String,
113 value: Vec<u8>,
114 ) -> HeaderResult<()> {
115 let fields = self.table.get_mut(&fields)?;
116 fields.append(self.hooks, name, value)?;
117 Ok(())
118 }
119
120 fn entries(&mut self, fields: Resource<FieldMap>) -> wasmtime::Result<Vec<(String, Vec<u8>)>> {
121 Ok(self
122 .table
123 .get(&fields)?
124 .iter()
125 .map(|(name, value)| (name.as_str().to_owned(), value.as_bytes().to_owned()))
126 .collect())
127 }
128
129 fn clone(&mut self, fields: Resource<FieldMap>) -> wasmtime::Result<Resource<FieldMap>> {
130 let mut fields = self.table.get(&fields)?.clone();
131 fields.set_mutable(self.ctx.field_size_limit);
132 let id = self.table.push(fields)?;
133 Ok(id)
134 }
135}
136
137impl types::HostIncomingRequest for WasiHttpCtxView<'_> {
138 fn method(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Method> {
139 let method = self.table.get(&id)?.method.clone();
140 Ok(method.into())
141 }
142 fn path_with_query(
143 &mut self,
144 id: Resource<HostIncomingRequest>,
145 ) -> wasmtime::Result<Option<String>> {
146 let req = self.table.get(&id)?;
147 Ok(req
148 .uri
149 .path_and_query()
150 .map(|path_and_query| path_and_query.as_str().to_owned()))
151 }
152 fn scheme(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Option<Scheme>> {
153 let req = self.table.get(&id)?;
154 Ok(Some(req.scheme.clone()))
155 }
156 fn authority(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Option<String>> {
157 let req = self.table.get(&id)?;
158 Ok(Some(req.authority.clone()))
159 }
160
161 fn headers(
162 &mut self,
163 id: Resource<HostIncomingRequest>,
164 ) -> wasmtime::Result<Resource<FieldMap>> {
165 let req = self.table.get(&id)?;
166 Ok(self.table.push(req.headers.clone())?)
167 }
168
169 fn consume(
170 &mut self,
171 id: Resource<HostIncomingRequest>,
172 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
173 let req = self.table.get_mut(&id)?;
174 match req.body.take() {
175 Some(body) => {
176 let id = self.table.push(body)?;
177 Ok(Ok(id))
178 }
179
180 None => Ok(Err(())),
181 }
182 }
183
184 fn drop(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<()> {
185 let _ = self.table.delete(id)?;
186 Ok(())
187 }
188}
189
190impl types::HostOutgoingRequest for WasiHttpCtxView<'_> {
191 fn new(
192 &mut self,
193 headers: Resource<FieldMap>,
194 ) -> wasmtime::Result<Resource<HostOutgoingRequest>> {
195 let mut headers = self.table.delete(headers)?;
196 headers.set_immutable();
197
198 self.table
199 .push(HostOutgoingRequest {
200 path_with_query: None,
201 authority: None,
202 method: types::Method::Get,
203 headers,
204 scheme: None,
205 body: None,
206 })
207 .context("[new_outgoing_request] pushing request")
208 }
209
210 fn body(
211 &mut self,
212 request: Resource<HostOutgoingRequest>,
213 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
214 let buffer_chunks = self.hooks.p2_outgoing_body_buffer_chunks();
215 let chunk_size = self.hooks.p2_outgoing_body_chunk_size();
216 let req = self
217 .table
218 .get_mut(&request)
219 .context("[outgoing_request_write] getting request")?;
220
221 if req.body.is_some() {
222 return Ok(Err(()));
223 }
224
225 let size = match get_content_length(&req.headers) {
226 Ok(size) => size,
227 Err(..) => return Ok(Err(())),
228 };
229
230 let (host_body, hyper_body) =
231 HostOutgoingBody::new(StreamContext::Request, size, buffer_chunks, chunk_size);
232
233 req.body = Some(hyper_body);
234
235 let outgoing_body = self.table.push(host_body)?;
238
239 Ok(Ok(outgoing_body))
240 }
241
242 fn drop(&mut self, request: Resource<HostOutgoingRequest>) -> wasmtime::Result<()> {
243 let _ = self.table.delete(request)?;
244 Ok(())
245 }
246
247 fn method(
248 &mut self,
249 request: wasmtime::component::Resource<types::OutgoingRequest>,
250 ) -> wasmtime::Result<Method> {
251 Ok(self.table.get(&request)?.method.clone())
252 }
253
254 fn set_method(
255 &mut self,
256 request: wasmtime::component::Resource<types::OutgoingRequest>,
257 method: Method,
258 ) -> wasmtime::Result<Result<(), ()>> {
259 let req = self.table.get_mut(&request)?;
260
261 if let Method::Other(s) = &method {
262 if let Err(_) = http::Method::from_str(s) {
263 return Ok(Err(()));
264 }
265 }
266
267 req.method = method;
268
269 Ok(Ok(()))
270 }
271
272 fn path_with_query(
273 &mut self,
274 request: wasmtime::component::Resource<types::OutgoingRequest>,
275 ) -> wasmtime::Result<Option<String>> {
276 Ok(self.table.get(&request)?.path_with_query.clone())
277 }
278
279 fn set_path_with_query(
280 &mut self,
281 request: wasmtime::component::Resource<types::OutgoingRequest>,
282 path_with_query: Option<String>,
283 ) -> wasmtime::Result<Result<(), ()>> {
284 let req = self.table.get_mut(&request)?;
285
286 if let Some(s) = path_with_query.as_ref() {
287 if let Err(_) = http::uri::PathAndQuery::from_str(s) {
288 return Ok(Err(()));
289 }
290 }
291
292 req.path_with_query = path_with_query;
293
294 Ok(Ok(()))
295 }
296
297 fn scheme(
298 &mut self,
299 request: wasmtime::component::Resource<types::OutgoingRequest>,
300 ) -> wasmtime::Result<Option<Scheme>> {
301 Ok(self.table.get(&request)?.scheme.clone())
302 }
303
304 fn set_scheme(
305 &mut self,
306 request: wasmtime::component::Resource<types::OutgoingRequest>,
307 scheme: Option<Scheme>,
308 ) -> wasmtime::Result<Result<(), ()>> {
309 let req = self.table.get_mut(&request)?;
310
311 if let Some(types::Scheme::Other(s)) = scheme.as_ref() {
312 if let Err(_) = http::uri::Scheme::from_str(s.as_str()) {
313 return Ok(Err(()));
314 }
315 }
316
317 req.scheme = scheme;
318
319 Ok(Ok(()))
320 }
321
322 fn authority(
323 &mut self,
324 request: wasmtime::component::Resource<types::OutgoingRequest>,
325 ) -> wasmtime::Result<Option<String>> {
326 Ok(self.table.get(&request)?.authority.clone())
327 }
328
329 fn set_authority(
330 &mut self,
331 request: wasmtime::component::Resource<types::OutgoingRequest>,
332 authority: Option<String>,
333 ) -> wasmtime::Result<Result<(), ()>> {
334 let req = self.table.get_mut(&request)?;
335
336 if let Some(s) = authority {
339 let Ok(parsed) = crate::parse_authority(s) else {
340 return Ok(Err(()));
341 };
342 req.authority = Some(parsed.as_str().into());
343 } else {
344 req.authority = None;
345 }
346
347 Ok(Ok(()))
348 }
349
350 fn headers(
351 &mut self,
352 request: wasmtime::component::Resource<types::OutgoingRequest>,
353 ) -> wasmtime::Result<wasmtime::component::Resource<FieldMap>> {
354 let req = self.table.get(&request)?;
355 let id = self.table.push(req.headers.clone())?;
356 Ok(id)
357 }
358}
359
360impl types::HostResponseOutparam for WasiHttpCtxView<'_> {
361 fn drop(&mut self, id: Resource<HostResponseOutparam>) -> wasmtime::Result<()> {
362 let _ = self.table.delete(id)?;
363 Ok(())
364 }
365 fn set(
366 &mut self,
367 id: Resource<HostResponseOutparam>,
368 resp: Result<Resource<HostOutgoingResponse>, types::ErrorCode>,
369 ) -> wasmtime::Result<()> {
370 let val = match resp {
371 Ok(resp) => Ok(self.table.delete(resp)?.try_into()?),
372 Err(e) => Err(e),
373 };
374
375 let resp = self.table.delete(id)?;
376 (resp.send)(val);
377 Ok(())
378 }
379
380 fn send_informational(
381 &mut self,
382 _id: Resource<HostResponseOutparam>,
383 _status: u16,
384 _headers: Resource<FieldMap>,
385 ) -> HttpResult<()> {
386 Err(HttpError::trap(format_err!("not implemented")))
387 }
388}
389
390impl types::HostIncomingResponse for WasiHttpCtxView<'_> {
391 fn drop(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<()> {
392 let _ = self
393 .table
394 .delete(response)
395 .context("[drop_incoming_response] deleting response")?;
396 Ok(())
397 }
398
399 fn status(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<StatusCode> {
400 let r = self
401 .table
402 .get(&response)
403 .context("[incoming_response_status] getting response")?;
404 Ok(r.status)
405 }
406
407 fn headers(
408 &mut self,
409 response: Resource<HostIncomingResponse>,
410 ) -> wasmtime::Result<Resource<FieldMap>> {
411 let resp = self.table.get(&response)?;
412 let id = self.table.push(resp.headers.clone())?;
413 Ok(id)
414 }
415
416 fn consume(
417 &mut self,
418 response: Resource<HostIncomingResponse>,
419 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
420 let r = self
421 .table
422 .get_mut(&response)
423 .context("[incoming_response_consume] getting response")?;
424
425 match r.body.take() {
426 Some(body) => {
427 let id = self.table.push(body)?;
428 Ok(Ok(id))
429 }
430
431 None => Ok(Err(())),
432 }
433 }
434}
435
436impl types::HostFutureTrailers for WasiHttpCtxView<'_> {
437 fn drop(&mut self, id: Resource<HostFutureTrailers>) -> wasmtime::Result<()> {
438 let _ = self
439 .table
440 .delete(id)
441 .context("[drop future-trailers] deleting future-trailers")?;
442 Ok(())
443 }
444
445 fn subscribe(
446 &mut self,
447 index: Resource<HostFutureTrailers>,
448 ) -> wasmtime::Result<Resource<DynPollable>> {
449 wasmtime_wasi::p2::subscribe(self.table, index)
450 }
451
452 fn get(
453 &mut self,
454 id: Resource<HostFutureTrailers>,
455 ) -> wasmtime::Result<Option<Result<Result<Option<Resource<Trailers>>, types::ErrorCode>, ()>>>
456 {
457 let trailers = self.table.get_mut(&id)?;
458 match trailers {
459 HostFutureTrailers::Waiting { .. } => return Ok(None),
460 HostFutureTrailers::Consumed => return Ok(Some(Err(()))),
461 HostFutureTrailers::Done(_) => {}
462 };
463
464 let res = match std::mem::replace(trailers, HostFutureTrailers::Consumed) {
465 HostFutureTrailers::Done(res) => res,
466 _ => unreachable!(),
467 };
468
469 let fields = match res {
470 Ok(Some(fields)) => fields,
471 Ok(None) => return Ok(Some(Ok(Ok(None)))),
472 Err(e) => {
473 let e = self.error_to_p2(e);
474 return Ok(Some(Ok(Err(e))));
475 }
476 };
477
478 let ts = self
479 .table
480 .push(FieldMap::new_immutable(self.hooks, fields))?;
481
482 Ok(Some(Ok(Ok(Some(ts)))))
483 }
484}
485
486impl types::HostIncomingBody for WasiHttpCtxView<'_> {
487 fn stream(
488 &mut self,
489 id: Resource<HostIncomingBody>,
490 ) -> wasmtime::Result<Result<Resource<DynInputStream>, ()>> {
491 let body = self.table.get_mut(&id)?;
492
493 if let Some(stream) = body.take_stream() {
494 let stream: DynInputStream = Box::new(stream);
495 let stream = self.table.push_child(stream, &id)?;
496 return Ok(Ok(stream));
497 }
498
499 Ok(Err(()))
500 }
501
502 fn finish(
503 &mut self,
504 id: Resource<HostIncomingBody>,
505 ) -> wasmtime::Result<Resource<HostFutureTrailers>> {
506 let body = self.table.delete(id)?;
507 let trailers = self.table.push(body.into_future_trailers())?;
508 Ok(trailers)
509 }
510
511 fn drop(&mut self, id: Resource<HostIncomingBody>) -> wasmtime::Result<()> {
512 let _ = self.table.delete(id)?;
513 Ok(())
514 }
515}
516
517impl types::HostOutgoingResponse for WasiHttpCtxView<'_> {
518 fn new(
519 &mut self,
520 headers: Resource<FieldMap>,
521 ) -> wasmtime::Result<Resource<HostOutgoingResponse>> {
522 let mut fields = self.table.delete(headers)?;
523 fields.set_immutable();
524
525 let id = self.table.push(HostOutgoingResponse {
526 status: http::StatusCode::OK,
527 headers: fields,
528 body: None,
529 })?;
530
531 Ok(id)
532 }
533
534 fn body(
535 &mut self,
536 id: Resource<HostOutgoingResponse>,
537 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
538 let buffer_chunks = self.hooks.p2_outgoing_body_buffer_chunks();
539 let chunk_size = self.hooks.p2_outgoing_body_chunk_size();
540 let resp = self.table.get_mut(&id)?;
541
542 if resp.body.is_some() {
543 return Ok(Err(()));
544 }
545
546 let size = match get_content_length(&resp.headers) {
547 Ok(size) => size,
548 Err(..) => return Ok(Err(())),
549 };
550
551 let (host, body) =
552 HostOutgoingBody::new(StreamContext::Response, size, buffer_chunks, chunk_size);
553
554 resp.body.replace(body);
555
556 let id = self.table.push(host)?;
557
558 Ok(Ok(id))
559 }
560
561 fn status_code(
562 &mut self,
563 id: Resource<HostOutgoingResponse>,
564 ) -> wasmtime::Result<types::StatusCode> {
565 Ok(self.table.get(&id)?.status.into())
566 }
567
568 fn set_status_code(
569 &mut self,
570 id: Resource<HostOutgoingResponse>,
571 status: types::StatusCode,
572 ) -> wasmtime::Result<Result<(), ()>> {
573 let resp = self.table.get_mut(&id)?;
574
575 match http::StatusCode::from_u16(status) {
576 Ok(status) => resp.status = status,
577 Err(_) => return Ok(Err(())),
578 };
579
580 Ok(Ok(()))
581 }
582
583 fn headers(
584 &mut self,
585 id: Resource<HostOutgoingResponse>,
586 ) -> wasmtime::Result<Resource<FieldMap>> {
587 let resp = self.table.get(&id)?;
588 Ok(self.table.push(resp.headers.clone())?)
589 }
590
591 fn drop(&mut self, id: Resource<HostOutgoingResponse>) -> wasmtime::Result<()> {
592 let _ = self.table.delete(id)?;
593 Ok(())
594 }
595}
596
597impl types::HostFutureIncomingResponse for WasiHttpCtxView<'_> {
598 fn drop(&mut self, id: Resource<HostFutureIncomingResponse>) -> wasmtime::Result<()> {
599 let _ = self.table.delete(id)?;
600 Ok(())
601 }
602
603 fn get(
604 &mut self,
605 id: Resource<HostFutureIncomingResponse>,
606 ) -> wasmtime::Result<
607 Option<Result<Result<Resource<HostIncomingResponse>, types::ErrorCode>, ()>>,
608 > {
609 let resp = self.table.get_mut(&id)?;
610
611 match resp {
612 HostFutureIncomingResponse::Pending(_) => return Ok(None),
613 HostFutureIncomingResponse::Consumed => return Ok(Some(Err(()))),
614 HostFutureIncomingResponse::Ready(_) => {}
615 }
616
617 let (resp, io) =
618 match std::mem::replace(resp, HostFutureIncomingResponse::Consumed).unwrap_ready() {
619 Ok(pair) => pair,
620 Err(e) => {
621 let e = self.error_to_p2(e);
622 return Ok(Some(Ok(Err(e))));
623 }
624 };
625
626 let (parts, body) = resp.into_parts();
627 let headers = FieldMap::new_immutable(self.hooks, parts.headers);
628
629 let resp = self.table.push(HostIncomingResponse {
630 status: parts.status.as_u16(),
631 headers,
632 body: Some({
633 let mut body = HostIncomingBody::new(body);
634 body.retain_worker(io);
635 body
636 }),
637 })?;
638
639 Ok(Some(Ok(Ok(resp))))
640 }
641
642 fn subscribe(
643 &mut self,
644 id: Resource<HostFutureIncomingResponse>,
645 ) -> wasmtime::Result<Resource<DynPollable>> {
646 wasmtime_wasi::p2::subscribe(self.table, id)
647 }
648}
649
650impl types::HostOutgoingBody for WasiHttpCtxView<'_> {
651 fn write(
652 &mut self,
653 id: Resource<HostOutgoingBody>,
654 ) -> wasmtime::Result<Result<Resource<DynOutputStream>, ()>> {
655 let body = self.table.get_mut(&id)?;
656 if let Some(stream) = body.take_output_stream() {
657 let id = self.table.push_child(stream, &id)?;
658 Ok(Ok(id))
659 } else {
660 Ok(Err(()))
661 }
662 }
663
664 fn finish(
665 &mut self,
666 id: Resource<HostOutgoingBody>,
667 ts: Option<Resource<Trailers>>,
668 ) -> HttpResult<()> {
669 let body = self.table.delete(id)?;
670
671 let ts = if let Some(ts) = ts {
672 Some(self.table.delete(ts)?)
673 } else {
674 None
675 };
676
677 body.finish(ts)?;
678 Ok(())
679 }
680
681 fn drop(&mut self, id: Resource<HostOutgoingBody>) -> wasmtime::Result<()> {
682 self.table.delete(id)?.abort();
683 Ok(())
684 }
685}
686
687impl types::HostRequestOptions for WasiHttpCtxView<'_> {
688 fn new(&mut self) -> wasmtime::Result<Resource<types::RequestOptions>> {
689 let id = self.table.push(types::RequestOptions::default())?;
690 Ok(id)
691 }
692
693 fn connect_timeout(
694 &mut self,
695 opts: Resource<types::RequestOptions>,
696 ) -> wasmtime::Result<Option<types::Duration>> {
697 let nanos = self.table.get(&opts)?.connect_timeout.map(|d| d.as_nanos());
698
699 if let Some(nanos) = nanos {
700 Ok(Some(nanos.try_into()?))
701 } else {
702 Ok(None)
703 }
704 }
705
706 fn set_connect_timeout(
707 &mut self,
708 opts: Resource<types::RequestOptions>,
709 duration: Option<types::Duration>,
710 ) -> wasmtime::Result<Result<(), ()>> {
711 self.table.get_mut(&opts)?.connect_timeout = duration.map(std::time::Duration::from_nanos);
712 Ok(Ok(()))
713 }
714
715 fn first_byte_timeout(
716 &mut self,
717 opts: Resource<types::RequestOptions>,
718 ) -> wasmtime::Result<Option<types::Duration>> {
719 let nanos = self
720 .table
721 .get(&opts)?
722 .first_byte_timeout
723 .map(|d| d.as_nanos());
724
725 if let Some(nanos) = nanos {
726 Ok(Some(nanos.try_into()?))
727 } else {
728 Ok(None)
729 }
730 }
731
732 fn set_first_byte_timeout(
733 &mut self,
734 opts: Resource<types::RequestOptions>,
735 duration: Option<types::Duration>,
736 ) -> wasmtime::Result<Result<(), ()>> {
737 self.table.get_mut(&opts)?.first_byte_timeout =
738 duration.map(std::time::Duration::from_nanos);
739 Ok(Ok(()))
740 }
741
742 fn between_bytes_timeout(
743 &mut self,
744 opts: Resource<types::RequestOptions>,
745 ) -> wasmtime::Result<Option<types::Duration>> {
746 let nanos = self
747 .table
748 .get(&opts)?
749 .between_bytes_timeout
750 .map(|d| d.as_nanos());
751
752 if let Some(nanos) = nanos {
753 Ok(Some(nanos.try_into()?))
754 } else {
755 Ok(None)
756 }
757 }
758
759 fn set_between_bytes_timeout(
760 &mut self,
761 opts: Resource<types::RequestOptions>,
762 duration: Option<types::Duration>,
763 ) -> wasmtime::Result<Result<(), ()>> {
764 self.table.get_mut(&opts)?.between_bytes_timeout =
765 duration.map(std::time::Duration::from_nanos);
766 Ok(Ok(()))
767 }
768
769 fn drop(&mut self, rep: Resource<types::RequestOptions>) -> wasmtime::Result<()> {
770 let _ = self.table.delete(rep)?;
771 Ok(())
772 }
773}
774
775mod named {
776 use crate::p2::bindings::http::types::{self, Method, Scheme, StatusCode, Trailers};
777 use crate::p2::bindings::named_imports::wasi::http::types as named_types;
778 use crate::p2::body::{HostFutureTrailers, HostIncomingBody, HostOutgoingBody};
779 use crate::p2::types::{
780 HostFutureIncomingResponse, HostIncomingRequest, HostIncomingResponse, HostOutgoingRequest,
781 HostOutgoingResponse, HostResponseOutparam,
782 };
783 use crate::p2::{HeaderError, HeaderResult, HttpError, HttpResult};
784 use crate::{FieldMap, WasiHttpNamedView};
785 use wasmtime::component::Resource;
786 use wasmtime_wasi::p2::{DynInputStream, DynOutputStream, DynPollable};
787 use wasmtime_wasi::{NamedId, WasiCtxNamedView};
788
789 impl<T> named_types::Host for WasiCtxNamedView<'_, T>
790 where
791 T: WasiHttpNamedView,
792 {
793 fn convert_error_code(&mut self, err: HttpError) -> wasmtime::Result<types::ErrorCode> {
794 err.downcast()
795 }
796
797 fn convert_header_error(
798 &mut self,
799 err: HeaderError,
800 ) -> wasmtime::Result<types::HeaderError> {
801 err.downcast()
802 }
803
804 fn http_error_code(
805 &mut self,
806 id: NamedId,
807 err: wasmtime::component::Resource<types::IoError>,
808 ) -> wasmtime::Result<Option<types::ErrorCode>> {
809 super::types::Host::http_error_code(&mut self.0.http(id), err)
810 }
811 }
812
813 impl<T> named_types::HostFields for WasiCtxNamedView<'_, T>
814 where
815 T: WasiHttpNamedView,
816 {
817 fn new(&mut self, id: NamedId) -> wasmtime::Result<Resource<FieldMap>> {
818 super::types::HostFields::new(&mut self.0.http(id))
819 }
820
821 fn from_list(
822 &mut self,
823 id: NamedId,
824 entries: Vec<(String, Vec<u8>)>,
825 ) -> HeaderResult<Resource<FieldMap>> {
826 super::types::HostFields::from_list(&mut self.0.http(id), entries)
827 }
828
829 fn drop(&mut self, id: NamedId, fields: Resource<FieldMap>) -> wasmtime::Result<()> {
830 super::types::HostFields::drop(&mut self.0.http(id), fields)
831 }
832
833 fn get(
834 &mut self,
835 id: NamedId,
836 fields: Resource<FieldMap>,
837 name: String,
838 ) -> wasmtime::Result<Vec<Vec<u8>>> {
839 super::types::HostFields::get(&mut self.0.http(id), fields, name)
840 }
841
842 fn has(
843 &mut self,
844 id: NamedId,
845 fields: Resource<FieldMap>,
846 name: String,
847 ) -> wasmtime::Result<bool> {
848 super::types::HostFields::has(&mut self.0.http(id), fields, name)
849 }
850
851 fn set(
852 &mut self,
853 id: NamedId,
854 fields: Resource<FieldMap>,
855 name: String,
856 values: Vec<Vec<u8>>,
857 ) -> HeaderResult<()> {
858 super::types::HostFields::set(&mut self.0.http(id), fields, name, values)
859 }
860
861 fn delete(
862 &mut self,
863 id: NamedId,
864 fields: Resource<FieldMap>,
865 name: String,
866 ) -> HeaderResult<()> {
867 super::types::HostFields::delete(&mut self.0.http(id), fields, name)
868 }
869
870 fn append(
871 &mut self,
872 id: NamedId,
873 fields: Resource<FieldMap>,
874 name: String,
875 value: Vec<u8>,
876 ) -> HeaderResult<()> {
877 super::types::HostFields::append(&mut self.0.http(id), fields, name, value)
878 }
879
880 fn entries(
881 &mut self,
882 id: NamedId,
883 fields: Resource<FieldMap>,
884 ) -> wasmtime::Result<Vec<(String, Vec<u8>)>> {
885 super::types::HostFields::entries(&mut self.0.http(id), fields)
886 }
887
888 fn clone(
889 &mut self,
890 id: NamedId,
891 fields: Resource<FieldMap>,
892 ) -> wasmtime::Result<Resource<FieldMap>> {
893 super::types::HostFields::clone(&mut self.0.http(id), fields)
894 }
895 }
896
897 impl<T> named_types::HostIncomingRequest for WasiCtxNamedView<'_, T>
898 where
899 T: WasiHttpNamedView,
900 {
901 fn method(
902 &mut self,
903 id: NamedId,
904 this: Resource<HostIncomingRequest>,
905 ) -> wasmtime::Result<Method> {
906 super::types::HostIncomingRequest::method(&mut self.0.http(id), this)
907 }
908
909 fn path_with_query(
910 &mut self,
911 id: NamedId,
912 this: Resource<HostIncomingRequest>,
913 ) -> wasmtime::Result<Option<String>> {
914 super::types::HostIncomingRequest::path_with_query(&mut self.0.http(id), this)
915 }
916
917 fn scheme(
918 &mut self,
919 id: NamedId,
920 this: Resource<HostIncomingRequest>,
921 ) -> wasmtime::Result<Option<Scheme>> {
922 super::types::HostIncomingRequest::scheme(&mut self.0.http(id), this)
923 }
924
925 fn authority(
926 &mut self,
927 id: NamedId,
928 this: Resource<HostIncomingRequest>,
929 ) -> wasmtime::Result<Option<String>> {
930 super::types::HostIncomingRequest::authority(&mut self.0.http(id), this)
931 }
932
933 fn headers(
934 &mut self,
935 id: NamedId,
936 this: Resource<HostIncomingRequest>,
937 ) -> wasmtime::Result<Resource<FieldMap>> {
938 super::types::HostIncomingRequest::headers(&mut self.0.http(id), this)
939 }
940
941 fn consume(
942 &mut self,
943 id: NamedId,
944 this: Resource<HostIncomingRequest>,
945 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
946 super::types::HostIncomingRequest::consume(&mut self.0.http(id), this)
947 }
948
949 fn drop(
950 &mut self,
951 id: NamedId,
952 this: Resource<HostIncomingRequest>,
953 ) -> wasmtime::Result<()> {
954 super::types::HostIncomingRequest::drop(&mut self.0.http(id), this)
955 }
956 }
957
958 impl<T> named_types::HostOutgoingRequest for WasiCtxNamedView<'_, T>
959 where
960 T: WasiHttpNamedView,
961 {
962 fn new(
963 &mut self,
964 id: NamedId,
965 headers: Resource<FieldMap>,
966 ) -> wasmtime::Result<Resource<HostOutgoingRequest>> {
967 super::types::HostOutgoingRequest::new(&mut self.0.http(id), headers)
968 }
969
970 fn body(
971 &mut self,
972 id: NamedId,
973 request: Resource<HostOutgoingRequest>,
974 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
975 super::types::HostOutgoingRequest::body(&mut self.0.http(id), request)
976 }
977
978 fn drop(
979 &mut self,
980 id: NamedId,
981 request: Resource<HostOutgoingRequest>,
982 ) -> wasmtime::Result<()> {
983 super::types::HostOutgoingRequest::drop(&mut self.0.http(id), request)
984 }
985
986 fn method(
987 &mut self,
988 id: NamedId,
989 request: wasmtime::component::Resource<types::OutgoingRequest>,
990 ) -> wasmtime::Result<Method> {
991 super::types::HostOutgoingRequest::method(&mut self.0.http(id), request)
992 }
993
994 fn set_method(
995 &mut self,
996 id: NamedId,
997 request: wasmtime::component::Resource<types::OutgoingRequest>,
998 method: Method,
999 ) -> wasmtime::Result<Result<(), ()>> {
1000 super::types::HostOutgoingRequest::set_method(&mut self.0.http(id), request, method)
1001 }
1002
1003 fn path_with_query(
1004 &mut self,
1005 id: NamedId,
1006 request: wasmtime::component::Resource<types::OutgoingRequest>,
1007 ) -> wasmtime::Result<Option<String>> {
1008 super::types::HostOutgoingRequest::path_with_query(&mut self.0.http(id), request)
1009 }
1010
1011 fn set_path_with_query(
1012 &mut self,
1013 id: NamedId,
1014 request: wasmtime::component::Resource<types::OutgoingRequest>,
1015 path_with_query: Option<String>,
1016 ) -> wasmtime::Result<Result<(), ()>> {
1017 super::types::HostOutgoingRequest::set_path_with_query(
1018 &mut self.0.http(id),
1019 request,
1020 path_with_query,
1021 )
1022 }
1023
1024 fn scheme(
1025 &mut self,
1026 id: NamedId,
1027 request: wasmtime::component::Resource<types::OutgoingRequest>,
1028 ) -> wasmtime::Result<Option<Scheme>> {
1029 super::types::HostOutgoingRequest::scheme(&mut self.0.http(id), request)
1030 }
1031
1032 fn set_scheme(
1033 &mut self,
1034 id: NamedId,
1035 request: wasmtime::component::Resource<types::OutgoingRequest>,
1036 scheme: Option<Scheme>,
1037 ) -> wasmtime::Result<Result<(), ()>> {
1038 super::types::HostOutgoingRequest::set_scheme(&mut self.0.http(id), request, scheme)
1039 }
1040
1041 fn authority(
1042 &mut self,
1043 id: NamedId,
1044 request: wasmtime::component::Resource<types::OutgoingRequest>,
1045 ) -> wasmtime::Result<Option<String>> {
1046 super::types::HostOutgoingRequest::authority(&mut self.0.http(id), request)
1047 }
1048
1049 fn set_authority(
1050 &mut self,
1051 id: NamedId,
1052 request: wasmtime::component::Resource<types::OutgoingRequest>,
1053 authority: Option<String>,
1054 ) -> wasmtime::Result<Result<(), ()>> {
1055 super::types::HostOutgoingRequest::set_authority(
1056 &mut self.0.http(id),
1057 request,
1058 authority,
1059 )
1060 }
1061
1062 fn headers(
1063 &mut self,
1064 id: NamedId,
1065 request: wasmtime::component::Resource<types::OutgoingRequest>,
1066 ) -> wasmtime::Result<wasmtime::component::Resource<FieldMap>> {
1067 super::types::HostOutgoingRequest::headers(&mut self.0.http(id), request)
1068 }
1069 }
1070
1071 impl<T> named_types::HostResponseOutparam for WasiCtxNamedView<'_, T>
1072 where
1073 T: WasiHttpNamedView,
1074 {
1075 fn drop(
1076 &mut self,
1077 id: NamedId,
1078 this: Resource<HostResponseOutparam>,
1079 ) -> wasmtime::Result<()> {
1080 super::types::HostResponseOutparam::drop(&mut self.0.http(id), this)
1081 }
1082
1083 fn set(
1084 &mut self,
1085 id: NamedId,
1086 this: Resource<HostResponseOutparam>,
1087 resp: Result<Resource<HostOutgoingResponse>, types::ErrorCode>,
1088 ) -> wasmtime::Result<()> {
1089 super::types::HostResponseOutparam::set(&mut self.0.http(id), this, resp)
1090 }
1091
1092 fn send_informational(
1093 &mut self,
1094 id: NamedId,
1095 _id: Resource<HostResponseOutparam>,
1096 _status: u16,
1097 _headers: Resource<FieldMap>,
1098 ) -> HttpResult<()> {
1099 super::types::HostResponseOutparam::send_informational(
1100 &mut self.0.http(id),
1101 _id,
1102 _status,
1103 _headers,
1104 )
1105 }
1106 }
1107
1108 impl<T> named_types::HostIncomingResponse for WasiCtxNamedView<'_, T>
1109 where
1110 T: WasiHttpNamedView,
1111 {
1112 fn drop(
1113 &mut self,
1114 id: NamedId,
1115 response: Resource<HostIncomingResponse>,
1116 ) -> wasmtime::Result<()> {
1117 super::types::HostIncomingResponse::drop(&mut self.0.http(id), response)
1118 }
1119
1120 fn status(
1121 &mut self,
1122 id: NamedId,
1123 response: Resource<HostIncomingResponse>,
1124 ) -> wasmtime::Result<StatusCode> {
1125 super::types::HostIncomingResponse::status(&mut self.0.http(id), response)
1126 }
1127
1128 fn headers(
1129 &mut self,
1130 id: NamedId,
1131 response: Resource<HostIncomingResponse>,
1132 ) -> wasmtime::Result<Resource<FieldMap>> {
1133 super::types::HostIncomingResponse::headers(&mut self.0.http(id), response)
1134 }
1135
1136 fn consume(
1137 &mut self,
1138 id: NamedId,
1139 response: Resource<HostIncomingResponse>,
1140 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
1141 super::types::HostIncomingResponse::consume(&mut self.0.http(id), response)
1142 }
1143 }
1144
1145 impl<T> named_types::HostFutureTrailers for WasiCtxNamedView<'_, T>
1146 where
1147 T: WasiHttpNamedView,
1148 {
1149 fn drop(
1150 &mut self,
1151 id: NamedId,
1152 this: Resource<HostFutureTrailers>,
1153 ) -> wasmtime::Result<()> {
1154 super::types::HostFutureTrailers::drop(&mut self.0.http(id), this)
1155 }
1156
1157 fn subscribe(
1158 &mut self,
1159 id: NamedId,
1160 index: Resource<HostFutureTrailers>,
1161 ) -> wasmtime::Result<Resource<DynPollable>> {
1162 super::types::HostFutureTrailers::subscribe(&mut self.0.http(id), index)
1163 }
1164
1165 fn get(
1166 &mut self,
1167 id: NamedId,
1168 this: Resource<HostFutureTrailers>,
1169 ) -> wasmtime::Result<
1170 Option<Result<Result<Option<Resource<Trailers>>, types::ErrorCode>, ()>>,
1171 > {
1172 super::types::HostFutureTrailers::get(&mut self.0.http(id), this)
1173 }
1174 }
1175
1176 impl<T> named_types::HostIncomingBody for WasiCtxNamedView<'_, T>
1177 where
1178 T: WasiHttpNamedView,
1179 {
1180 fn stream(
1181 &mut self,
1182 id: NamedId,
1183 this: Resource<HostIncomingBody>,
1184 ) -> wasmtime::Result<Result<Resource<DynInputStream>, ()>> {
1185 super::types::HostIncomingBody::stream(&mut self.0.http(id), this)
1186 }
1187
1188 fn finish(
1189 &mut self,
1190 id: NamedId,
1191 this: Resource<HostIncomingBody>,
1192 ) -> wasmtime::Result<Resource<HostFutureTrailers>> {
1193 super::types::HostIncomingBody::finish(&mut self.0.http(id), this)
1194 }
1195
1196 fn drop(&mut self, id: NamedId, this: Resource<HostIncomingBody>) -> wasmtime::Result<()> {
1197 super::types::HostIncomingBody::drop(&mut self.0.http(id), this)
1198 }
1199 }
1200
1201 impl<T> named_types::HostOutgoingResponse for WasiCtxNamedView<'_, T>
1202 where
1203 T: WasiHttpNamedView,
1204 {
1205 fn new(
1206 &mut self,
1207 id: NamedId,
1208 headers: Resource<FieldMap>,
1209 ) -> wasmtime::Result<Resource<HostOutgoingResponse>> {
1210 super::types::HostOutgoingResponse::new(&mut self.0.http(id), headers)
1211 }
1212
1213 fn body(
1214 &mut self,
1215 id: NamedId,
1216 this: Resource<HostOutgoingResponse>,
1217 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
1218 super::types::HostOutgoingResponse::body(&mut self.0.http(id), this)
1219 }
1220
1221 fn status_code(
1222 &mut self,
1223 id: NamedId,
1224 this: Resource<HostOutgoingResponse>,
1225 ) -> wasmtime::Result<types::StatusCode> {
1226 super::types::HostOutgoingResponse::status_code(&mut self.0.http(id), this)
1227 }
1228
1229 fn set_status_code(
1230 &mut self,
1231 id: NamedId,
1232 this: Resource<HostOutgoingResponse>,
1233 status: types::StatusCode,
1234 ) -> wasmtime::Result<Result<(), ()>> {
1235 super::types::HostOutgoingResponse::set_status_code(&mut self.0.http(id), this, status)
1236 }
1237
1238 fn headers(
1239 &mut self,
1240 id: NamedId,
1241 this: Resource<HostOutgoingResponse>,
1242 ) -> wasmtime::Result<Resource<FieldMap>> {
1243 super::types::HostOutgoingResponse::headers(&mut self.0.http(id), this)
1244 }
1245
1246 fn drop(
1247 &mut self,
1248 id: NamedId,
1249 this: Resource<HostOutgoingResponse>,
1250 ) -> wasmtime::Result<()> {
1251 super::types::HostOutgoingResponse::drop(&mut self.0.http(id), this)
1252 }
1253 }
1254
1255 impl<T> named_types::HostFutureIncomingResponse for WasiCtxNamedView<'_, T>
1256 where
1257 T: WasiHttpNamedView,
1258 {
1259 fn drop(
1260 &mut self,
1261 id: NamedId,
1262 this: Resource<HostFutureIncomingResponse>,
1263 ) -> wasmtime::Result<()> {
1264 super::types::HostFutureIncomingResponse::drop(&mut self.0.http(id), this)
1265 }
1266
1267 fn get(
1268 &mut self,
1269 id: NamedId,
1270 this: Resource<HostFutureIncomingResponse>,
1271 ) -> wasmtime::Result<
1272 Option<Result<Result<Resource<HostIncomingResponse>, types::ErrorCode>, ()>>,
1273 > {
1274 super::types::HostFutureIncomingResponse::get(&mut self.0.http(id), this)
1275 }
1276
1277 fn subscribe(
1278 &mut self,
1279 id: NamedId,
1280 this: Resource<HostFutureIncomingResponse>,
1281 ) -> wasmtime::Result<Resource<DynPollable>> {
1282 super::types::HostFutureIncomingResponse::subscribe(&mut self.0.http(id), this)
1283 }
1284 }
1285
1286 impl<T> named_types::HostOutgoingBody for WasiCtxNamedView<'_, T>
1287 where
1288 T: WasiHttpNamedView,
1289 {
1290 fn write(
1291 &mut self,
1292 id: NamedId,
1293 this: Resource<HostOutgoingBody>,
1294 ) -> wasmtime::Result<Result<Resource<DynOutputStream>, ()>> {
1295 super::types::HostOutgoingBody::write(&mut self.0.http(id), this)
1296 }
1297
1298 fn finish(
1299 &mut self,
1300 id: NamedId,
1301 this: Resource<HostOutgoingBody>,
1302 ts: Option<Resource<Trailers>>,
1303 ) -> HttpResult<()> {
1304 super::types::HostOutgoingBody::finish(&mut self.0.http(id), this, ts)
1305 }
1306
1307 fn drop(&mut self, id: NamedId, this: Resource<HostOutgoingBody>) -> wasmtime::Result<()> {
1308 super::types::HostOutgoingBody::drop(&mut self.0.http(id), this)
1309 }
1310 }
1311
1312 impl<T> named_types::HostRequestOptions for WasiCtxNamedView<'_, T>
1313 where
1314 T: WasiHttpNamedView,
1315 {
1316 fn new(&mut self, id: NamedId) -> wasmtime::Result<Resource<types::RequestOptions>> {
1317 super::types::HostRequestOptions::new(&mut self.0.http(id))
1318 }
1319
1320 fn connect_timeout(
1321 &mut self,
1322 id: NamedId,
1323 opts: Resource<types::RequestOptions>,
1324 ) -> wasmtime::Result<Option<types::Duration>> {
1325 super::types::HostRequestOptions::connect_timeout(&mut self.0.http(id), opts)
1326 }
1327
1328 fn set_connect_timeout(
1329 &mut self,
1330 id: NamedId,
1331 opts: Resource<types::RequestOptions>,
1332 duration: Option<types::Duration>,
1333 ) -> wasmtime::Result<Result<(), ()>> {
1334 super::types::HostRequestOptions::set_connect_timeout(
1335 &mut self.0.http(id),
1336 opts,
1337 duration,
1338 )
1339 }
1340
1341 fn first_byte_timeout(
1342 &mut self,
1343 id: NamedId,
1344 opts: Resource<types::RequestOptions>,
1345 ) -> wasmtime::Result<Option<types::Duration>> {
1346 super::types::HostRequestOptions::first_byte_timeout(&mut self.0.http(id), opts)
1347 }
1348
1349 fn set_first_byte_timeout(
1350 &mut self,
1351 id: NamedId,
1352 opts: Resource<types::RequestOptions>,
1353 duration: Option<types::Duration>,
1354 ) -> wasmtime::Result<Result<(), ()>> {
1355 super::types::HostRequestOptions::set_first_byte_timeout(
1356 &mut self.0.http(id),
1357 opts,
1358 duration,
1359 )
1360 }
1361
1362 fn between_bytes_timeout(
1363 &mut self,
1364 id: NamedId,
1365 opts: Resource<types::RequestOptions>,
1366 ) -> wasmtime::Result<Option<types::Duration>> {
1367 super::types::HostRequestOptions::between_bytes_timeout(&mut self.0.http(id), opts)
1368 }
1369
1370 fn set_between_bytes_timeout(
1371 &mut self,
1372 id: NamedId,
1373 opts: Resource<types::RequestOptions>,
1374 duration: Option<types::Duration>,
1375 ) -> wasmtime::Result<Result<(), ()>> {
1376 super::types::HostRequestOptions::set_between_bytes_timeout(
1377 &mut self.0.http(id),
1378 opts,
1379 duration,
1380 )
1381 }
1382
1383 fn drop(
1384 &mut self,
1385 id: NamedId,
1386 rep: Resource<types::RequestOptions>,
1387 ) -> wasmtime::Result<()> {
1388 super::types::HostRequestOptions::drop(&mut self.0.http(id), rep)
1389 }
1390 }
1391}