1use crate::{
4 HttpError, HttpResult, 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, anyhow};
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 if let Err(_) = http::uri::Authority::from_str(s.as_str()) {
515 return Ok(Err(()));
516 }
517 }
518
519 req.authority = authority;
520
521 Ok(Ok(()))
522 }
523
524 fn headers(
525 &mut self,
526 request: wasmtime::component::Resource<types::OutgoingRequest>,
527 ) -> wasmtime::Result<wasmtime::component::Resource<Headers>> {
528 let _ = self
529 .table()
530 .get(&request)
531 .context("[outgoing_request_headers] getting request")?;
532
533 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
534 &mut elem
535 .downcast_mut::<types::OutgoingRequest>()
536 .unwrap()
537 .headers
538 }
539
540 let id = self.table().push_child(
541 HostFields::Ref {
542 parent: request.rep(),
543 get_fields,
544 },
545 &request,
546 )?;
547
548 Ok(id)
549 }
550}
551
552impl<T> crate::bindings::http::types::HostResponseOutparam for WasiHttpImpl<T>
553where
554 T: WasiHttpView,
555{
556 fn drop(&mut self, id: Resource<HostResponseOutparam>) -> wasmtime::Result<()> {
557 let _ = self.table().delete(id)?;
558 Ok(())
559 }
560 fn set(
561 &mut self,
562 id: Resource<HostResponseOutparam>,
563 resp: Result<Resource<HostOutgoingResponse>, types::ErrorCode>,
564 ) -> wasmtime::Result<()> {
565 let val = match resp {
566 Ok(resp) => Ok(self.table().delete(resp)?.try_into()?),
567 Err(e) => Err(e),
568 };
569
570 let resp = self.table().delete(id)?;
571 let _ = resp.result.send(val);
576 Ok(())
577 }
578
579 fn send_informational(
580 &mut self,
581 _id: Resource<HostResponseOutparam>,
582 _status: u16,
583 _headers: Resource<Headers>,
584 ) -> HttpResult<()> {
585 Err(HttpError::trap(anyhow!("not implemented")))
586 }
587}
588
589impl<T> crate::bindings::http::types::HostIncomingResponse for WasiHttpImpl<T>
590where
591 T: WasiHttpView,
592{
593 fn drop(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<()> {
594 let _ = self
595 .table()
596 .delete(response)
597 .context("[drop_incoming_response] deleting response")?;
598 Ok(())
599 }
600
601 fn status(&mut self, response: Resource<HostIncomingResponse>) -> wasmtime::Result<StatusCode> {
602 let r = self
603 .table()
604 .get(&response)
605 .context("[incoming_response_status] getting response")?;
606 Ok(r.status)
607 }
608
609 fn headers(
610 &mut self,
611 response: Resource<HostIncomingResponse>,
612 ) -> wasmtime::Result<Resource<Headers>> {
613 let _ = self
614 .table()
615 .get(&response)
616 .context("[incoming_response_headers] getting response")?;
617
618 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
619 &mut elem.downcast_mut::<HostIncomingResponse>().unwrap().headers
620 }
621
622 let id = self.table().push_child(
623 HostFields::Ref {
624 parent: response.rep(),
625 get_fields,
626 },
627 &response,
628 )?;
629
630 Ok(id)
631 }
632
633 fn consume(
634 &mut self,
635 response: Resource<HostIncomingResponse>,
636 ) -> wasmtime::Result<Result<Resource<HostIncomingBody>, ()>> {
637 let table = self.table();
638 let r = table
639 .get_mut(&response)
640 .context("[incoming_response_consume] getting response")?;
641
642 match r.body.take() {
643 Some(body) => {
644 let id = self.table().push(body)?;
645 Ok(Ok(id))
646 }
647
648 None => Ok(Err(())),
649 }
650 }
651}
652
653impl<T> crate::bindings::http::types::HostFutureTrailers for WasiHttpImpl<T>
654where
655 T: WasiHttpView,
656{
657 fn drop(&mut self, id: Resource<HostFutureTrailers>) -> wasmtime::Result<()> {
658 let _ = self
659 .table()
660 .delete(id)
661 .context("[drop future-trailers] deleting future-trailers")?;
662 Ok(())
663 }
664
665 fn subscribe(
666 &mut self,
667 index: Resource<HostFutureTrailers>,
668 ) -> wasmtime::Result<Resource<DynPollable>> {
669 wasmtime_wasi::p2::subscribe(self.table(), index)
670 }
671
672 fn get(
673 &mut self,
674 id: Resource<HostFutureTrailers>,
675 ) -> wasmtime::Result<Option<Result<Result<Option<Resource<Trailers>>, types::ErrorCode>, ()>>>
676 {
677 let trailers = self.table().get_mut(&id)?;
678 match trailers {
679 HostFutureTrailers::Waiting(_) => return Ok(None),
680 HostFutureTrailers::Consumed => return Ok(Some(Err(()))),
681 HostFutureTrailers::Done(_) => {}
682 };
683
684 let res = match std::mem::replace(trailers, HostFutureTrailers::Consumed) {
685 HostFutureTrailers::Done(res) => res,
686 _ => unreachable!(),
687 };
688
689 let mut fields = match res {
690 Ok(Some(fields)) => fields,
691 Ok(None) => return Ok(Some(Ok(Ok(None)))),
692 Err(e) => return Ok(Some(Ok(Err(e)))),
693 };
694
695 remove_forbidden_headers(self, &mut fields);
696
697 let ts = self.table().push(HostFields::Owned { fields })?;
698
699 Ok(Some(Ok(Ok(Some(ts)))))
700 }
701}
702
703impl<T> crate::bindings::http::types::HostIncomingBody for WasiHttpImpl<T>
704where
705 T: WasiHttpView,
706{
707 fn stream(
708 &mut self,
709 id: Resource<HostIncomingBody>,
710 ) -> wasmtime::Result<Result<Resource<DynInputStream>, ()>> {
711 let body = self.table().get_mut(&id)?;
712
713 if let Some(stream) = body.take_stream() {
714 let stream: DynInputStream = Box::new(stream);
715 let stream = self.table().push_child(stream, &id)?;
716 return Ok(Ok(stream));
717 }
718
719 Ok(Err(()))
720 }
721
722 fn finish(
723 &mut self,
724 id: Resource<HostIncomingBody>,
725 ) -> wasmtime::Result<Resource<HostFutureTrailers>> {
726 let body = self.table().delete(id)?;
727 let trailers = self.table().push(body.into_future_trailers())?;
728 Ok(trailers)
729 }
730
731 fn drop(&mut self, id: Resource<HostIncomingBody>) -> wasmtime::Result<()> {
732 let _ = self.table().delete(id)?;
733 Ok(())
734 }
735}
736
737impl<T> crate::bindings::http::types::HostOutgoingResponse for WasiHttpImpl<T>
738where
739 T: WasiHttpView,
740{
741 fn new(
742 &mut self,
743 headers: Resource<Headers>,
744 ) -> wasmtime::Result<Resource<HostOutgoingResponse>> {
745 let fields = move_fields(self.table(), headers)?;
746
747 let id = self.table().push(HostOutgoingResponse {
748 status: http::StatusCode::OK,
749 headers: fields,
750 body: None,
751 })?;
752
753 Ok(id)
754 }
755
756 fn body(
757 &mut self,
758 id: Resource<HostOutgoingResponse>,
759 ) -> wasmtime::Result<Result<Resource<HostOutgoingBody>, ()>> {
760 let buffer_chunks = self.outgoing_body_buffer_chunks();
761 let chunk_size = self.outgoing_body_chunk_size();
762 let resp = self.table().get_mut(&id)?;
763
764 if resp.body.is_some() {
765 return Ok(Err(()));
766 }
767
768 let size = match get_content_length(&resp.headers) {
769 Ok(size) => size,
770 Err(e) => return Ok(Err(e)),
771 };
772
773 let (host, body) =
774 HostOutgoingBody::new(StreamContext::Response, size, buffer_chunks, chunk_size);
775
776 resp.body.replace(body);
777
778 let id = self.table().push(host)?;
779
780 Ok(Ok(id))
781 }
782
783 fn status_code(
784 &mut self,
785 id: Resource<HostOutgoingResponse>,
786 ) -> wasmtime::Result<types::StatusCode> {
787 Ok(self.table().get(&id)?.status.into())
788 }
789
790 fn set_status_code(
791 &mut self,
792 id: Resource<HostOutgoingResponse>,
793 status: types::StatusCode,
794 ) -> wasmtime::Result<Result<(), ()>> {
795 let resp = self.table().get_mut(&id)?;
796
797 match http::StatusCode::from_u16(status) {
798 Ok(status) => resp.status = status,
799 Err(_) => return Ok(Err(())),
800 };
801
802 Ok(Ok(()))
803 }
804
805 fn headers(
806 &mut self,
807 id: Resource<HostOutgoingResponse>,
808 ) -> wasmtime::Result<Resource<types::Headers>> {
809 let _ = self.table().get(&id)?;
811
812 fn get_fields(elem: &mut dyn Any) -> &mut FieldMap {
813 let resp = elem.downcast_mut::<HostOutgoingResponse>().unwrap();
814 &mut resp.headers
815 }
816
817 Ok(self.table().push_child(
818 HostFields::Ref {
819 parent: id.rep(),
820 get_fields,
821 },
822 &id,
823 )?)
824 }
825
826 fn drop(&mut self, id: Resource<HostOutgoingResponse>) -> wasmtime::Result<()> {
827 let _ = self.table().delete(id)?;
828 Ok(())
829 }
830}
831
832impl<T> crate::bindings::http::types::HostFutureIncomingResponse for WasiHttpImpl<T>
833where
834 T: WasiHttpView,
835{
836 fn drop(&mut self, id: Resource<HostFutureIncomingResponse>) -> wasmtime::Result<()> {
837 let _ = self.table().delete(id)?;
838 Ok(())
839 }
840
841 fn get(
842 &mut self,
843 id: Resource<HostFutureIncomingResponse>,
844 ) -> wasmtime::Result<
845 Option<Result<Result<Resource<HostIncomingResponse>, types::ErrorCode>, ()>>,
846 > {
847 let resp = self.table().get_mut(&id)?;
848
849 match resp {
850 HostFutureIncomingResponse::Pending(_) => return Ok(None),
851 HostFutureIncomingResponse::Consumed => return Ok(Some(Err(()))),
852 HostFutureIncomingResponse::Ready(_) => {}
853 }
854
855 let resp =
856 match std::mem::replace(resp, HostFutureIncomingResponse::Consumed).unwrap_ready() {
857 Err(e) => {
858 let e = e.downcast::<types::ErrorCode>()?;
860 return Ok(Some(Ok(Err(e))));
861 }
862
863 Ok(Ok(resp)) => resp,
864 Ok(Err(e)) => return Ok(Some(Ok(Err(e)))),
865 };
866
867 let (mut parts, body) = resp.resp.into_parts();
868
869 remove_forbidden_headers(self, &mut parts.headers);
870
871 let resp = self.table().push(HostIncomingResponse {
872 status: parts.status.as_u16(),
873 headers: parts.headers,
874 body: Some({
875 let mut body = HostIncomingBody::new(body, resp.between_bytes_timeout);
876 if let Some(worker) = resp.worker {
877 body.retain_worker(worker);
878 }
879 body
880 }),
881 })?;
882
883 Ok(Some(Ok(Ok(resp))))
884 }
885
886 fn subscribe(
887 &mut self,
888 id: Resource<HostFutureIncomingResponse>,
889 ) -> wasmtime::Result<Resource<DynPollable>> {
890 wasmtime_wasi::p2::subscribe(self.table(), id)
891 }
892}
893
894impl<T> crate::bindings::http::types::HostOutgoingBody for WasiHttpImpl<T>
895where
896 T: WasiHttpView,
897{
898 fn write(
899 &mut self,
900 id: Resource<HostOutgoingBody>,
901 ) -> wasmtime::Result<Result<Resource<DynOutputStream>, ()>> {
902 let body = self.table().get_mut(&id)?;
903 if let Some(stream) = body.take_output_stream() {
904 let id = self.table().push_child(stream, &id)?;
905 Ok(Ok(id))
906 } else {
907 Ok(Err(()))
908 }
909 }
910
911 fn finish(
912 &mut self,
913 id: Resource<HostOutgoingBody>,
914 ts: Option<Resource<Trailers>>,
915 ) -> crate::HttpResult<()> {
916 let body = self.table().delete(id)?;
917
918 let ts = if let Some(ts) = ts {
919 Some(move_fields(self.table(), ts)?)
920 } else {
921 None
922 };
923
924 body.finish(ts)?;
925 Ok(())
926 }
927
928 fn drop(&mut self, id: Resource<HostOutgoingBody>) -> wasmtime::Result<()> {
929 self.table().delete(id)?.abort();
930 Ok(())
931 }
932}
933
934impl<T> crate::bindings::http::types::HostRequestOptions for WasiHttpImpl<T>
935where
936 T: WasiHttpView,
937{
938 fn new(&mut self) -> wasmtime::Result<Resource<types::RequestOptions>> {
939 let id = self.table().push(types::RequestOptions::default())?;
940 Ok(id)
941 }
942
943 fn connect_timeout(
944 &mut self,
945 opts: Resource<types::RequestOptions>,
946 ) -> wasmtime::Result<Option<types::Duration>> {
947 let nanos = self
948 .table()
949 .get(&opts)?
950 .connect_timeout
951 .map(|d| d.as_nanos());
952
953 if let Some(nanos) = nanos {
954 Ok(Some(nanos.try_into()?))
955 } else {
956 Ok(None)
957 }
958 }
959
960 fn set_connect_timeout(
961 &mut self,
962 opts: Resource<types::RequestOptions>,
963 duration: Option<types::Duration>,
964 ) -> wasmtime::Result<Result<(), ()>> {
965 self.table().get_mut(&opts)?.connect_timeout =
966 duration.map(std::time::Duration::from_nanos);
967 Ok(Ok(()))
968 }
969
970 fn first_byte_timeout(
971 &mut self,
972 opts: Resource<types::RequestOptions>,
973 ) -> wasmtime::Result<Option<types::Duration>> {
974 let nanos = self
975 .table()
976 .get(&opts)?
977 .first_byte_timeout
978 .map(|d| d.as_nanos());
979
980 if let Some(nanos) = nanos {
981 Ok(Some(nanos.try_into()?))
982 } else {
983 Ok(None)
984 }
985 }
986
987 fn set_first_byte_timeout(
988 &mut self,
989 opts: Resource<types::RequestOptions>,
990 duration: Option<types::Duration>,
991 ) -> wasmtime::Result<Result<(), ()>> {
992 self.table().get_mut(&opts)?.first_byte_timeout =
993 duration.map(std::time::Duration::from_nanos);
994 Ok(Ok(()))
995 }
996
997 fn between_bytes_timeout(
998 &mut self,
999 opts: Resource<types::RequestOptions>,
1000 ) -> wasmtime::Result<Option<types::Duration>> {
1001 let nanos = self
1002 .table()
1003 .get(&opts)?
1004 .between_bytes_timeout
1005 .map(|d| d.as_nanos());
1006
1007 if let Some(nanos) = nanos {
1008 Ok(Some(nanos.try_into()?))
1009 } else {
1010 Ok(None)
1011 }
1012 }
1013
1014 fn set_between_bytes_timeout(
1015 &mut self,
1016 opts: Resource<types::RequestOptions>,
1017 duration: Option<types::Duration>,
1018 ) -> wasmtime::Result<Result<(), ()>> {
1019 self.table().get_mut(&opts)?.between_bytes_timeout =
1020 duration.map(std::time::Duration::from_nanos);
1021 Ok(Ok(()))
1022 }
1023
1024 fn drop(&mut self, rep: Resource<types::RequestOptions>) -> wasmtime::Result<()> {
1025 let _ = self.table().delete(rep)?;
1026 Ok(())
1027 }
1028}