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