spin_http/
trigger.rs

1use serde::{Deserialize, Serialize};
2use spin_factor_outbound_http::wasi_2023_10_18::ProxyIndices as ProxyIndices2023_10_18;
3use spin_factor_outbound_http::wasi_2023_11_10::ProxyIndices as ProxyIndices2023_11_10;
4use wasmtime::component::InstancePre;
5use wasmtime_wasi::p2::bindings::CommandIndices;
6use wasmtime_wasi_http::bindings::ProxyIndices;
7
8#[derive(Clone, Debug, Default, Deserialize, Serialize)]
9#[serde(deny_unknown_fields)]
10pub struct Metadata {
11    // The based url
12    #[serde(default = "default_base")]
13    pub base: String,
14}
15
16pub fn default_base() -> String {
17    "/".into()
18}
19
20/// The type of http handler export used by a component.
21pub enum HandlerType {
22    Spin,
23    Wagi(CommandIndices),
24    Wasi0_2(ProxyIndices),
25    Wasi2023_11_10(ProxyIndices2023_11_10),
26    Wasi2023_10_18(ProxyIndices2023_10_18),
27}
28
29/// The `incoming-handler` export for `wasi:http` version rc-2023-10-18
30const WASI_HTTP_EXPORT_2023_10_18: &str = "wasi:http/incoming-handler@0.2.0-rc-2023-10-18";
31/// The `incoming-handler` export for `wasi:http` version rc-2023-11-10
32const WASI_HTTP_EXPORT_2023_11_10: &str = "wasi:http/incoming-handler@0.2.0-rc-2023-11-10";
33/// The `incoming-handler` export prefix for all `wasi:http` 0.2 versions
34const WASI_HTTP_EXPORT_0_2_PREFIX: &str = "wasi:http/incoming-handler@0.2";
35/// The `inbound-http` export for `fermyon:spin`
36const SPIN_HTTP_EXPORT: &str = "fermyon:spin/inbound-http";
37
38impl HandlerType {
39    /// Determine the handler type from the exports of a component.
40    pub fn from_instance_pre<T>(pre: &InstancePre<T>) -> anyhow::Result<HandlerType> {
41        let mut candidates = Vec::new();
42        if let Ok(indices) = ProxyIndices::new(pre) {
43            candidates.push(HandlerType::Wasi0_2(indices));
44        }
45        if let Ok(indices) = ProxyIndices2023_10_18::new(pre) {
46            candidates.push(HandlerType::Wasi2023_10_18(indices));
47        }
48        if let Ok(indices) = ProxyIndices2023_11_10::new(pre) {
49            candidates.push(HandlerType::Wasi2023_11_10(indices));
50        }
51        if pre
52            .component()
53            .get_export_index(None, SPIN_HTTP_EXPORT)
54            .is_some()
55        {
56            candidates.push(HandlerType::Spin);
57        }
58
59        match candidates.len() {
60            0 => {
61                anyhow::bail!(
62                    "Expected component to export one of \
63                    `{WASI_HTTP_EXPORT_2023_10_18}`, \
64                    `{WASI_HTTP_EXPORT_2023_11_10}`, \
65                    `{WASI_HTTP_EXPORT_0_2_PREFIX}.*`, \
66                     or `{SPIN_HTTP_EXPORT}` but it exported none of those. \
67                     This may mean the component handles a different trigger, or that its `wasi:http` export is newer then those supported by Spin. \
68                     If you're sure this is an HTTP module, check if a Spin upgrade is available: this may handle the newer version."
69                )
70            }
71            1 => Ok(candidates.pop().unwrap()),
72            _ => anyhow::bail!(
73                "component exports multiple different handlers but \
74                     it's expected to export only one"
75            ),
76        }
77    }
78}