1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
pub use crate::types::{WasiHttpCtx, WasiHttpView};

pub mod body;
pub mod http_impl;
pub mod proxy;
pub mod types;
pub mod types_impl;

pub mod bindings {
    wasmtime::component::bindgen!({
        path: "wit",
        interfaces: "
            import wasi:http/incoming-handler@0.2.0-rc-2023-10-18;
            import wasi:http/outgoing-handler@0.2.0-rc-2023-10-18;
            import wasi:http/types@0.2.0-rc-2023-10-18;
        ",
        tracing: true,
        async: false,
        with: {
            "wasi:io/streams": wasmtime_wasi::preview2::bindings::io::streams,
            "wasi:io/poll": wasmtime_wasi::preview2::bindings::io::poll,

            "wasi:http/types/outgoing-body": super::body::HostOutgoingBody,
            "wasi:http/types/future-incoming-response": super::types::HostFutureIncomingResponse,
            "wasi:http/types/outgoing-response": super::types::HostOutgoingResponse,
            "wasi:http/types/future-trailers": super::body::HostFutureTrailers,
            "wasi:http/types/incoming-body": super::body::HostIncomingBody,
            "wasi:http/types/incoming-response": super::types::HostIncomingResponse,
            "wasi:http/types/response-outparam": super::types::HostResponseOutparam,
            "wasi:http/types/outgoing-request": super::types::HostOutgoingRequest,
            "wasi:http/types/incoming-request": super::types::HostIncomingRequest,
            "wasi:http/types/fields": super::types::HostFields,
        }
    });

    pub use wasi::http;
}

impl From<wasmtime_wasi::preview2::TableError> for crate::bindings::http::types::Error {
    fn from(err: wasmtime_wasi::preview2::TableError) -> Self {
        Self::UnexpectedError(err.to_string())
    }
}

impl From<anyhow::Error> for crate::bindings::http::types::Error {
    fn from(err: anyhow::Error) -> Self {
        Self::UnexpectedError(err.to_string())
    }
}

impl From<std::io::Error> for crate::bindings::http::types::Error {
    fn from(err: std::io::Error) -> Self {
        let message = err.to_string();
        match err.kind() {
            std::io::ErrorKind::InvalidInput => Self::InvalidUrl(message),
            std::io::ErrorKind::AddrNotAvailable => Self::InvalidUrl(message),
            _ => {
                if message.starts_with("failed to lookup address information") {
                    Self::InvalidUrl("invalid dnsname".to_string())
                } else {
                    Self::ProtocolError(message)
                }
            }
        }
    }
}

impl From<http::Error> for crate::bindings::http::types::Error {
    fn from(err: http::Error) -> Self {
        Self::InvalidUrl(err.to_string())
    }
}

impl From<hyper::Error> for crate::bindings::http::types::Error {
    fn from(err: hyper::Error) -> Self {
        let message = err.message().to_string();
        if err.is_timeout() {
            Self::TimeoutError(message)
        } else if err.is_parse_status() || err.is_user() {
            Self::InvalidUrl(message)
        } else if err.is_body_write_aborted()
            || err.is_canceled()
            || err.is_closed()
            || err.is_incomplete_message()
            || err.is_parse()
        {
            Self::ProtocolError(message)
        } else {
            Self::UnexpectedError(message)
        }
    }
}

impl From<tokio::time::error::Elapsed> for crate::bindings::http::types::Error {
    fn from(err: tokio::time::error::Elapsed) -> Self {
        Self::TimeoutError(err.to_string())
    }
}

#[cfg(not(any(target_arch = "riscv64", target_arch = "s390x")))]
impl From<rustls::client::InvalidDnsNameError> for crate::bindings::http::types::Error {
    fn from(_err: rustls::client::InvalidDnsNameError) -> Self {
        Self::InvalidUrl("invalid dnsname".to_string())
    }
}