1use crate::bindings::http::types::{self, Headers, Method, Scheme, StatusCode, Trailers};
4use crate::body::{HostFutureTrailers, HostIncomingBody, HostOutgoingBody, StreamContext};
5use crate::types::{
6 FieldMap, HostFields, HostFutureIncomingResponse, HostIncomingRequest, HostIncomingResponse,
7 HostOutgoingRequest, HostOutgoingResponse, HostResponseOutparam, remove_forbidden_headers,
8};
9use crate::{HttpError, HttpResult, WasiHttpImpl, WasiHttpView, get_content_length};
10use anyhow::{Context, anyhow};
11use std::any::Any;
12use std::str::FromStr;
13use wasmtime::component::{Resource, ResourceTable, ResourceTableError};
14use wasmtime_wasi::p2::{DynInputStream, DynOutputStream, DynPollable};
15
16impl<T> crate::bindings::http::types::Host for WasiHttpImpl<T>
17where
18 T: WasiHttpView,
19{
20 fn convert_error_code(&mut self, err: crate::HttpError) -> wasmtime::Result<types::ErrorCode> {
21 err.downcast()
22 }
23
24 fn http_error_code(
25 &mut self,
26 err: wasmtime::component::Resource<types::IoError>,
27 ) -> wasmtime::Result<Option<types::ErrorCode>> {
28 let e = self.table().get(&err)?;
29 Ok(e.downcast_ref::<types::ErrorCode>().cloned())
30 }
31}
32
33fn move_fields(
36 table: &mut ResourceTable,
37 id: Resource<HostFields>,
38) -> Result<FieldMap, ResourceTableError> {
39 match table.delete(id)? {
40 HostFields::Ref { parent, get_fields } => {
41 let entry = table.get_any_mut(parent)?;
42 Ok(get_fields(entry).clone())
43 }
44
45 HostFields::Owned { fields } => Ok(fields),
46 }
47}
48
49fn get_fields<'a>(
50 table: &'a mut ResourceTable,
51 id: &Resource<HostFields>,
52) -> wasmtime::Result<&'a FieldMap> {
53 let fields = table.get(&id)?;
54 if let HostFields::Ref { parent, get_fields } = *fields {
55 let entry = table.get_any_mut(parent)?;
56 return Ok(get_fields(entry));
57 }
58
59 match table.get_mut(&id)? {
60 HostFields::Owned { fields } => Ok(fields),
61 HostFields::Ref { .. } => unreachable!(),
65 }
66}
67
68fn get_fields_mut<'a>(
69 table: &'a mut ResourceTable,
70 id: &Resource<HostFields>,
71) -> wasmtime::Result<Result<&'a mut FieldMap, types::HeaderError>> {
72 match table.get_mut(&id)? {
73 HostFields::Owned { fields } => Ok(Ok(fields)),
74 HostFields::Ref { .. } => Ok(Err(types::HeaderError::Immutable)),
75 }
76}
77
78impl<T> crate::bindings::http::types::HostFields for WasiHttpImpl<T>
79where
80 T: WasiHttpView,
81{
82 fn new(&mut self) -> wasmtime::Result<Resource<HostFields>> {
83 let id = self
84 .table()
85 .push(HostFields::Owned {
86 fields: hyper::HeaderMap::new(),
87 })
88 .context("[new_fields] pushing fields")?;
89
90 Ok(id)
91 }
92
93 fn from_list(
94 &mut self,
95 entries: Vec<(String, Vec<u8>)>,
96 ) -> wasmtime::Result<Result<Resource<HostFields>, types::HeaderError>> {
97 let mut fields = hyper::HeaderMap::new();
98
99 for (header, value) in entries {
100 let header = match hyper::header::HeaderName::from_bytes(header.as_bytes()) {
101 Ok(header) => header,
102 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
103 };
104
105 if self.is_forbidden_header(&header) {
106 return Ok(Err(types::HeaderError::Forbidden));
107 }
108
109 let value = match hyper::header::HeaderValue::from_bytes(&value) {
110 Ok(value) => value,
111 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
112 };
113
114 fields.append(header, value);
115 }
116
117 let id = self
118 .table()
119 .push(HostFields::Owned { fields })
120 .context("[new_fields] pushing fields")?;
121
122 Ok(Ok(id))
123 }
124
125 fn drop(&mut self, fields: Resource<HostFields>) -> wasmtime::Result<()> {
126 self.table()
127 .delete(fields)
128 .context("[drop_fields] deleting fields")?;
129 Ok(())
130 }
131
132 fn get(
133 &mut self,
134 fields: Resource<HostFields>,
135 name: String,
136 ) -> wasmtime::Result<Vec<Vec<u8>>> {
137 let fields = get_fields(self.table(), &fields).context("[fields_get] getting fields")?;
138
139 let header = match hyper::header::HeaderName::from_bytes(name.as_bytes()) {
140 Ok(header) => header,
141 Err(_) => return Ok(vec![]),
142 };
143
144 if !fields.contains_key(&header) {
145 return Ok(vec![]);
146 }
147
148 let res = fields
149 .get_all(&header)
150 .into_iter()
151 .map(|val| val.as_bytes().to_owned())
152 .collect();
153 Ok(res)
154 }
155
156 fn has(&mut self, fields: Resource<HostFields>, name: String) -> wasmtime::Result<bool> {
157 let fields = get_fields(self.table(), &fields).context("[fields_get] getting fields")?;
158
159 match hyper::header::HeaderName::from_bytes(name.as_bytes()) {
160 Ok(header) => Ok(fields.contains_key(&header)),
161 Err(_) => Ok(false),
162 }
163 }
164
165 fn set(
166 &mut self,
167 fields: Resource<HostFields>,
168 name: String,
169 byte_values: Vec<Vec<u8>>,
170 ) -> wasmtime::Result<Result<(), types::HeaderError>> {
171 let header = match hyper::header::HeaderName::from_bytes(name.as_bytes()) {
172 Ok(header) => header,
173 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
174 };
175
176 if self.is_forbidden_header(&header) {
177 return Ok(Err(types::HeaderError::Forbidden));
178 }
179
180 let mut values = Vec::with_capacity(byte_values.len());
181 for value in byte_values {
182 match hyper::header::HeaderValue::from_bytes(&value) {
183 Ok(value) => values.push(value),
184 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
185 }
186 }
187
188 Ok(get_fields_mut(self.table(), &fields)
189 .context("[fields_set] getting mutable fields")?
190 .map(|fields| {
191 fields.remove(&header);
192 for value in values {
193 fields.append(&header, value);
194 }
195 }))
196 }
197
198 fn delete(
199 &mut self,
200 fields: Resource<HostFields>,
201 name: String,
202 ) -> wasmtime::Result<Result<(), types::HeaderError>> {
203 let header = match hyper::header::HeaderName::from_bytes(name.as_bytes()) {
204 Ok(header) => header,
205 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
206 };
207
208 if self.is_forbidden_header(&header) {
209 return Ok(Err(types::HeaderError::Forbidden));
210 }
211
212 Ok(get_fields_mut(self.table(), &fields)?.map(|fields| {
213 fields.remove(header);
214 }))
215 }
216
217 fn append(
218 &mut self,
219 fields: Resource<HostFields>,
220 name: String,
221 value: Vec<u8>,
222 ) -> wasmtime::Result<Result<(), types::HeaderError>> {
223 let header = match hyper::header::HeaderName::from_bytes(name.as_bytes()) {
224 Ok(header) => header,
225 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
226 };
227
228 if self.is_forbidden_header(&header) {
229 return Ok(Err(types::HeaderError::Forbidden));
230 }
231
232 let value = match hyper::header::HeaderValue::from_bytes(&value) {
233 Ok(value) => value,
234 Err(_) => return Ok(Err(types::HeaderError::InvalidSyntax)),
235 };
236
237 Ok(get_fields_mut(self.table(), &fields)
238 .context("[fields_append] getting mutable fields")?
239 .map(|fields| {
240 fields.append(header, value);
241 }))
242 }
243
244 fn entries(
245 &mut self,
246 fields: Resource<HostFields>,
247 ) -> wasmtime::Result<Vec<(String, Vec<u8>)>> {
248 Ok(get_fields(self.table(), &fields)?
249 .iter()
250 .map(|(name, value)| (name.as_str().to_owned(), value.as_bytes().to_owned()))
251 .collect())
252 }
253
254 fn clone(&mut self, fields: Resource<HostFields>) -> wasmtime::Result<Resource<HostFields>> {
255 let fields = get_fields(self.table(), &fields)
256 .context("[fields_clone] getting fields")?
257 .clone();
258
259 let id = self
260 .table()
261 .push(HostFields::Owned { fields })
262 .context("[fields_clone] pushing fields")?;
263
264 Ok(id)
265 }
266}
267
268impl<T> crate::bindings::http::types::HostIncomingRequest for WasiHttpImpl<T>
269where
270 T: WasiHttpView,
271{
272 fn method(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Method> {
273 let method = self.table().get(&id)?.parts.method.clone();
274 Ok(method.into())
275 }
276 fn path_with_query(
277 &mut self,
278 id: Resource<HostIncomingRequest>,
279 ) -> wasmtime::Result<Option<String>> {
280 let req = self.table().get(&id)?;
281 Ok(req
282 .parts
283 .uri
284 .path_and_query()
285 .map(|path_and_query| path_and_query.as_str().to_owned()))
286 }
287 fn scheme(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Option<Scheme>> {
288 let req = self.table().get(&id)?;
289 Ok(Some(req.scheme.clone()))
290 }
291 fn authority(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<Option<String>> {
292 let req = self.table().get(&id)?;
293 Ok(Some(req.authority.clone()))
294 }
295
296 fn headers(
297 &mut self,
298 id: Resource<HostIncomingRequest>,
299 ) -> wasmtime::Result<Resource<Headers>> {
300 let _ = self.table().get(&id)?;
301
302 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
303 &mut elem
304 .downcast_mut::<HostIncomingRequest>()
305 .unwrap()
306 .parts
307 .headers
308 }
309
310 let headers = self.table().push_child(
311 HostFields::Ref {
312 parent: id.rep(),
313 get_fields,
314 },
315 &id,
316 )?;
317
318 Ok(headers)
319 }
320
321 fn consume(
322 &mut self,
323 id: Resource<HostIncomingRequest>,
324 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
325 let req = self.table().get_mut(&id)?;
326 match req.body.take() {
327 Some(body) => {
328 let id = self.table().push(body)?;
329 Ok(Ok(id))
330 }
331
332 None => Ok(Err(())),
333 }
334 }
335
336 fn drop(&mut self, id: Resource<HostIncomingRequest>) -> wasmtime::Result<()> {
337 let _ = self.table().delete(id)?;
338 Ok(())
339 }
340}
341
342impl<T> crate::bindings::http::types::HostOutgoingRequest for WasiHttpImpl<T>
343where
344 T: WasiHttpView,
345{
346 fn new(
347 &mut self,
348 headers: Resource<Headers>,
349 ) -> wasmtime::Result<Resource<HostOutgoingRequest>> {
350 let headers = move_fields(self.table(), headers)?;
351
352 self.table()
353 .push(HostOutgoingRequest {
354 path_with_query: None,
355 authority: None,
356 method: types::Method::Get,
357 headers,
358 scheme: None,
359 body: None,
360 })
361 .context("[new_outgoing_request] pushing request")
362 }
363
364 fn body(
365 &mut self,
366 request: Resource<HostOutgoingRequest>,
367 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
368 let buffer_chunks = self.outgoing_body_buffer_chunks();
369 let chunk_size = self.outgoing_body_chunk_size();
370 let req = self
371 .table()
372 .get_mut(&request)
373 .context("[outgoing_request_write] getting request")?;
374
375 if req.body.is_some() {
376 return Ok(Err(()));
377 }
378
379 let size = match get_content_length(&req.headers) {
380 Ok(size) => size,
381 Err(..) => return Ok(Err(())),
382 };
383
384 let (host_body, hyper_body) =
385 HostOutgoingBody::new(StreamContext::Request, size, buffer_chunks, chunk_size);
386
387 req.body = Some(hyper_body);
388
389 let outgoing_body = self.table().push(host_body)?;
392
393 Ok(Ok(outgoing_body))
394 }
395
396 fn drop(&mut self, request: Resource<HostOutgoingRequest>) -> wasmtime::Result<()> {
397 let _ = self.table().delete(request)?;
398 Ok(())
399 }
400
401 fn method(
402 &mut self,
403 request: wasmtime::component::Resource<types::OutgoingRequest>,
404 ) -> wasmtime::Result<Method> {
405 Ok(self.table().get(&request)?.method.clone())
406 }
407
408 fn set_method(
409 &mut self,
410 request: wasmtime::component::Resource<types::OutgoingRequest>,
411 method: Method,
412 ) -> wasmtime::Result<Result<(), ()>> {
413 let req = self.table().get_mut(&request)?;
414
415 if let Method::Other(s) = &method {
416 if let Err(_) = http::Method::from_str(s) {
417 return Ok(Err(()));
418 }
419 }
420
421 req.method = method;
422
423 Ok(Ok(()))
424 }
425
426 fn path_with_query(
427 &mut self,
428 request: wasmtime::component::Resource<types::OutgoingRequest>,
429 ) -> wasmtime::Result<Option<String>> {
430 Ok(self.table().get(&request)?.path_with_query.clone())
431 }
432
433 fn set_path_with_query(
434 &mut self,
435 request: wasmtime::component::Resource<types::OutgoingRequest>,
436 path_with_query: Option<String>,
437 ) -> wasmtime::Result<Result<(), ()>> {
438 let req = self.table().get_mut(&request)?;
439
440 if let Some(s) = path_with_query.as_ref() {
441 if let Err(_) = http::uri::PathAndQuery::from_str(s) {
442 return Ok(Err(()));
443 }
444 }
445
446 req.path_with_query = path_with_query;
447
448 Ok(Ok(()))
449 }
450
451 fn scheme(
452 &mut self,
453 request: wasmtime::component::Resource<types::OutgoingRequest>,
454 ) -> wasmtime::Result<Option<Scheme>> {
455 Ok(self.table().get(&request)?.scheme.clone())
456 }
457
458 fn set_scheme(
459 &mut self,
460 request: wasmtime::component::Resource<types::OutgoingRequest>,
461 scheme: Option<Scheme>,
462 ) -> wasmtime::Result<Result<(), ()>> {
463 let req = self.table().get_mut(&request)?;
464
465 if let Some(types::Scheme::Other(s)) = scheme.as_ref() {
466 if let Err(_) = http::uri::Scheme::from_str(s.as_str()) {
467 return Ok(Err(()));
468 }
469 }
470
471 req.scheme = scheme;
472
473 Ok(Ok(()))
474 }
475
476 fn authority(
477 &mut self,
478 request: wasmtime::component::Resource<types::OutgoingRequest>,
479 ) -> wasmtime::Result<Option<String>> {
480 Ok(self.table().get(&request)?.authority.clone())
481 }
482
483 fn set_authority(
484 &mut self,
485 request: wasmtime::component::Resource<types::OutgoingRequest>,
486 authority: Option<String>,
487 ) -> wasmtime::Result<Result<(), ()>> {
488 let req = self.table().get_mut(&request)?;
489
490 if let Some(s) = authority.as_ref() {
491 if let Err(_) = http::uri::Authority::from_str(s.as_str()) {
492 return Ok(Err(()));
493 }
494 }
495
496 req.authority = authority;
497
498 Ok(Ok(()))
499 }
500
501 fn headers(
502 &mut self,
503 request: wasmtime::component::Resource<types::OutgoingRequest>,
504 ) -> wasmtime::Result<wasmtime::component::Resource<Headers>> {
505 let _ = self
506 .table()
507 .get(&request)
508 .context("[outgoing_request_headers] getting request")?;
509
510 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
511 &mut elem
512 .downcast_mut::<types::OutgoingRequest>()
513 .unwrap()
514 .headers
515 }
516
517 let id = self.table().push_child(
518 HostFields::Ref {
519 parent: request.rep(),
520 get_fields,
521 },
522 &request,
523 )?;
524
525 Ok(id)
526 }
527}
528
529impl<T> crate::bindings::http::types::HostResponseOutparam for WasiHttpImpl<T>
530where
531 T: WasiHttpView,
532{
533 fn drop(&mut self, id: Resource<HostResponseOutparam>) -> wasmtime::Result<()> {
534 let _ = self.table().delete(id)?;
535 Ok(())
536 }
537 fn set(
538 &mut self,
539 id: Resource<HostResponseOutparam>,
540 resp: Result<Resource<HostOutgoingResponse>, types::ErrorCode>,
541 ) -> wasmtime::Result<()> {
542 let val = match resp {
543 Ok(resp) => Ok(self.table().delete(resp)?.try_into()?),
544 Err(e) => Err(e),
545 };
546
547 let resp = self.table().delete(id)?;
548 let _ = resp.result.send(val);
553 Ok(())
554 }
555
556 fn send_informational(
557 &mut self,
558 _id: Resource<HostResponseOutparam>,
559 _status: u16,
560 _headers: Resource<Headers>,
561 ) -> HttpResult<()> {
562 Err(HttpError::trap(anyhow!("not implemented")))
563 }
564}
565
566impl<T> crate::bindings::http::types::HostIncomingResponse for WasiHttpImpl<T>
567where
568 T: WasiHttpView,
569{
570 fn drop(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<()> {
571 let _ = self
572 .table()
573 .delete(response)
574 .context("[drop_incoming_response] deleting response")?;
575 Ok(())
576 }
577
578 fn status(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<StatusCode> {
579 let r = self
580 .table()
581 .get(&response)
582 .context("[incoming_response_status] getting response")?;
583 Ok(r.status)
584 }
585
586 fn headers(
587 &mut self,
588 response: Resource<HostIncomingResponse>,
589 ) -> wasmtime::Result<Resource<Headers>> {
590 let _ = self
591 .table()
592 .get(&response)
593 .context("[incoming_response_headers] getting response")?;
594
595 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
596 &mut elem.downcast_mut::<HostIncomingResponse>().unwrap().headers
597 }
598
599 let id = self.table().push_child(
600 HostFields::Ref {
601 parent: response.rep(),
602 get_fields,
603 },
604 &response,
605 )?;
606
607 Ok(id)
608 }
609
610 fn consume(
611 &mut self,
612 response: Resource<HostIncomingResponse>,
613 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
614 let table = self.table();
615 let r = table
616 .get_mut(&response)
617 .context("[incoming_response_consume] getting response")?;
618
619 match r.body.take() {
620 Some(body) => {
621 let id = self.table().push(body)?;
622 Ok(Ok(id))
623 }
624
625 None => Ok(Err(())),
626 }
627 }
628}
629
630impl<T> crate::bindings::http::types::HostFutureTrailers for WasiHttpImpl<T>
631where
632 T: WasiHttpView,
633{
634 fn drop(&mut self, id: Resource<HostFutureTrailers>) -> wasmtime::Result<()> {
635 let _ = self
636 .table()
637 .delete(id)
638 .context("[drop future-trailers] deleting future-trailers")?;
639 Ok(())
640 }
641
642 fn subscribe(
643 &mut self,
644 index: Resource<HostFutureTrailers>,
645 ) -> wasmtime::Result<Resource<DynPollable>> {
646 wasmtime_wasi::p2::subscribe(self.table(), index)
647 }
648
649 fn get(
650 &mut self,
651 id: Resource<HostFutureTrailers>,
652 ) -> wasmtime::Result<Option<Result<Result<Option<Resource<Trailers>>, types::ErrorCode>, ()>>>
653 {
654 let trailers = self.table().get_mut(&id)?;
655 match trailers {
656 HostFutureTrailers::Waiting(_) => return Ok(None),
657 HostFutureTrailers::Consumed => return Ok(Some(Err(()))),
658 HostFutureTrailers::Done(_) => {}
659 };
660
661 let res = match std::mem::replace(trailers, HostFutureTrailers::Consumed) {
662 HostFutureTrailers::Done(res) => res,
663 _ => unreachable!(),
664 };
665
666 let mut fields = match res {
667 Ok(Some(fields)) => fields,
668 Ok(None) => return Ok(Some(Ok(Ok(None)))),
669 Err(e) => return Ok(Some(Ok(Err(e)))),
670 };
671
672 remove_forbidden_headers(self, &mut fields);
673
674 let ts = self.table().push(HostFields::Owned { fields })?;
675
676 Ok(Some(Ok(Ok(Some(ts)))))
677 }
678}
679
680impl<T> crate::bindings::http::types::HostIncomingBody for WasiHttpImpl<T>
681where
682 T: WasiHttpView,
683{
684 fn stream(
685 &mut self,
686 id: Resource<HostIncomingBody>,
687 ) -> wasmtime::Result<Result<Resource<DynInputStream>, ()>> {
688 let body = self.table().get_mut(&id)?;
689
690 if let Some(stream) = body.take_stream() {
691 let stream: DynInputStream = Box::new(stream);
692 let stream = self.table().push_child(stream, &id)?;
693 return Ok(Ok(stream));
694 }
695
696 Ok(Err(()))
697 }
698
699 fn finish(
700 &mut self,
701 id: Resource<HostIncomingBody>,
702 ) -> wasmtime::Result<Resource<HostFutureTrailers>> {
703 let body = self.table().delete(id)?;
704 let trailers = self.table().push(body.into_future_trailers())?;
705 Ok(trailers)
706 }
707
708 fn drop(&mut self, id: Resource<HostIncomingBody>) -> wasmtime::Result<()> {
709 let _ = self.table().delete(id)?;
710 Ok(())
711 }
712}
713
714impl<T> crate::bindings::http::types::HostOutgoingResponse for WasiHttpImpl<T>
715where
716 T: WasiHttpView,
717{
718 fn new(
719 &mut self,
720 headers: Resource<Headers>,
721 ) -> wasmtime::Result<Resource<HostOutgoingResponse>> {
722 let fields = move_fields(self.table(), headers)?;
723
724 let id = self.table().push(HostOutgoingResponse {
725 status: http::StatusCode::OK,
726 headers: fields,
727 body: None,
728 })?;
729
730 Ok(id)
731 }
732
733 fn body(
734 &mut self,
735 id: Resource<HostOutgoingResponse>,
736 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
737 let buffer_chunks = self.outgoing_body_buffer_chunks();
738 let chunk_size = self.outgoing_body_chunk_size();
739 let resp = self.table().get_mut(&id)?;
740
741 if resp.body.is_some() {
742 return Ok(Err(()));
743 }
744
745 let size = match get_content_length(&resp.headers) {
746 Ok(size) => size,
747 Err(..) => return Ok(Err(())),
748 };
749
750 let (host, body) =
751 HostOutgoingBody::new(StreamContext::Response, size, buffer_chunks, chunk_size);
752
753 resp.body.replace(body);
754
755 let id = self.table().push(host)?;
756
757 Ok(Ok(id))
758 }
759
760 fn status_code(
761 &mut self,
762 id: Resource<HostOutgoingResponse>,
763 ) -> wasmtime::Result<types::StatusCode> {
764 Ok(self.table().get(&id)?.status.into())
765 }
766
767 fn set_status_code(
768 &mut self,
769 id: Resource<HostOutgoingResponse>,
770 status: types::StatusCode,
771 ) -> wasmtime::Result<Result<(), ()>> {
772 let resp = self.table().get_mut(&id)?;
773
774 match http::StatusCode::from_u16(status) {
775 Ok(status) => resp.status = status,
776 Err(_) => return Ok(Err(())),
777 };
778
779 Ok(Ok(()))
780 }
781
782 fn headers(
783 &mut self,
784 id: Resource<HostOutgoingResponse>,
785 ) -> wasmtime::Result<Resource<types::Headers>> {
786 let _ = self.table().get(&id)?;
788
789 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
790 let resp = elem.downcast_mut::<HostOutgoingResponse>().unwrap();
791 &mut resp.headers
792 }
793
794 Ok(self.table().push_child(
795 HostFields::Ref {
796 parent: id.rep(),
797 get_fields,
798 },
799 &id,
800 )?)
801 }
802
803 fn drop(&mut self, id: Resource<HostOutgoingResponse>) -> wasmtime::Result<()> {
804 let _ = self.table().delete(id)?;
805 Ok(())
806 }
807}
808
809impl<T> crate::bindings::http::types::HostFutureIncomingResponse for WasiHttpImpl<T>
810where
811 T: WasiHttpView,
812{
813 fn drop(&mut self, id: Resource<HostFutureIncomingResponse>) -> wasmtime::Result<()> {
814 let _ = self.table().delete(id)?;
815 Ok(())
816 }
817
818 fn get(
819 &mut self,
820 id: Resource<HostFutureIncomingResponse>,
821 ) -> wasmtime::Result<
822 Option<Result<Result<Resource<HostIncomingResponse>, types::ErrorCode>, ()>>,
823 > {
824 let resp = self.table().get_mut(&id)?;
825
826 match resp {
827 HostFutureIncomingResponse::Pending(_) => return Ok(None),
828 HostFutureIncomingResponse::Consumed => return Ok(Some(Err(()))),
829 HostFutureIncomingResponse::Ready(_) => {}
830 }
831
832 let resp =
833 match std::mem::replace(resp, HostFutureIncomingResponse::Consumed).unwrap_ready() {
834 Err(e) => {
835 let e = e.downcast::<types::ErrorCode>()?;
837 return Ok(Some(Ok(Err(e))));
838 }
839
840 Ok(Ok(resp)) => resp,
841 Ok(Err(e)) => return Ok(Some(Ok(Err(e)))),
842 };
843
844 let (mut parts, body) = resp.resp.into_parts();
845
846 remove_forbidden_headers(self, &mut parts.headers);
847
848 let resp = self.table().push(HostIncomingResponse {
849 status: parts.status.as_u16(),
850 headers: parts.headers,
851 body: Some({
852 let mut body = HostIncomingBody::new(body, resp.between_bytes_timeout);
853 if let Some(worker) = resp.worker {
854 body.retain_worker(worker);
855 }
856 body
857 }),
858 })?;
859
860 Ok(Some(Ok(Ok(resp))))
861 }
862
863 fn subscribe(
864 &mut self,
865 id: Resource<HostFutureIncomingResponse>,
866 ) -> wasmtime::Result<Resource<DynPollable>> {
867 wasmtime_wasi::p2::subscribe(self.table(), id)
868 }
869}
870
871impl<T> crate::bindings::http::types::HostOutgoingBody for WasiHttpImpl<T>
872where
873 T: WasiHttpView,
874{
875 fn write(
876 &mut self,
877 id: Resource<HostOutgoingBody>,
878 ) -> wasmtime::Result<Result<Resource<DynOutputStream>, ()>> {
879 let body = self.table().get_mut(&id)?;
880 if let Some(stream) = body.take_output_stream() {
881 let id = self.table().push_child(stream, &id)?;
882 Ok(Ok(id))
883 } else {
884 Ok(Err(()))
885 }
886 }
887
888 fn finish(
889 &mut self,
890 id: Resource<HostOutgoingBody>,
891 ts: Option<Resource<Trailers>>,
892 ) -> crate::HttpResult<()> {
893 let body = self.table().delete(id)?;
894
895 let ts = if let Some(ts) = ts {
896 Some(move_fields(self.table(), ts)?)
897 } else {
898 None
899 };
900
901 body.finish(ts)?;
902 Ok(())
903 }
904
905 fn drop(&mut self, id: Resource<HostOutgoingBody>) -> wasmtime::Result<()> {
906 self.table().delete(id)?.abort();
907 Ok(())
908 }
909}
910
911impl<T> crate::bindings::http::types::HostRequestOptions for WasiHttpImpl<T>
912where
913 T: WasiHttpView,
914{
915 fn new(&mut self) -> wasmtime::Result<Resource<types::RequestOptions>> {
916 let id = self.table().push(types::RequestOptions::default())?;
917 Ok(id)
918 }
919
920 fn connect_timeout(
921 &mut self,
922 opts: Resource<types::RequestOptions>,
923 ) -> wasmtime::Result<Option<types::Duration>> {
924 let nanos = self
925 .table()
926 .get(&opts)?
927 .connect_timeout
928 .map(|d| d.as_nanos());
929
930 if let Some(nanos) = nanos {
931 Ok(Some(nanos.try_into()?))
932 } else {
933 Ok(None)
934 }
935 }
936
937 fn set_connect_timeout(
938 &mut self,
939 opts: Resource<types::RequestOptions>,
940 duration: Option<types::Duration>,
941 ) -> wasmtime::Result<Result<(), ()>> {
942 self.table().get_mut(&opts)?.connect_timeout =
943 duration.map(std::time::Duration::from_nanos);
944 Ok(Ok(()))
945 }
946
947 fn first_byte_timeout(
948 &mut self,
949 opts: Resource<types::RequestOptions>,
950 ) -> wasmtime::Result<Option<types::Duration>> {
951 let nanos = self
952 .table()
953 .get(&opts)?
954 .first_byte_timeout
955 .map(|d| d.as_nanos());
956
957 if let Some(nanos) = nanos {
958 Ok(Some(nanos.try_into()?))
959 } else {
960 Ok(None)
961 }
962 }
963
964 fn set_first_byte_timeout(
965 &mut self,
966 opts: Resource<types::RequestOptions>,
967 duration: Option<types::Duration>,
968 ) -> wasmtime::Result<Result<(), ()>> {
969 self.table().get_mut(&opts)?.first_byte_timeout =
970 duration.map(std::time::Duration::from_nanos);
971 Ok(Ok(()))
972 }
973
974 fn between_bytes_timeout(
975 &mut self,
976 opts: Resource<types::RequestOptions>,
977 ) -> wasmtime::Result<Option<types::Duration>> {
978 let nanos = self
979 .table()
980 .get(&opts)?
981 .between_bytes_timeout
982 .map(|d| d.as_nanos());
983
984 if let Some(nanos) = nanos {
985 Ok(Some(nanos.try_into()?))
986 } else {
987 Ok(None)
988 }
989 }
990
991 fn set_between_bytes_timeout(
992 &mut self,
993 opts: Resource<types::RequestOptions>,
994 duration: Option<types::Duration>,
995 ) -> wasmtime::Result<Result<(), ()>> {
996 self.table().get_mut(&opts)?.between_bytes_timeout =
997 duration.map(std::time::Duration::from_nanos);
998 Ok(Ok(()))
999 }
1000
1001 fn drop(&mut self, rep: Resource<types::RequestOptions>) -> wasmtime::Result<()> {
1002 let _ = self.table().delete(rep)?;
1003 Ok(())
1004 }
1005}