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