Skip to content

Commit 284725b

Browse files
committed
Migrate outbound-http to new core
Signed-off-by: Lann Martin <lann.martin@fermyon.com>
1 parent de864b1 commit 284725b

File tree

12 files changed

+164
-209
lines changed

12 files changed

+164
-209
lines changed

Cargo.lock

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/loader/src/bindle/mod.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,24 @@ mod connection;
1010
/// Bindle helper functions.
1111
mod utils;
1212

13-
use crate::{
14-
bindle::{
15-
config::{RawAppManifest, RawComponentManifest},
16-
utils::{find_manifest, parcels_in_group},
17-
},
18-
validation::{parse_allowed_http_hosts, validate_allowed_http_hosts},
19-
};
13+
use std::path::Path;
14+
2015
use anyhow::{anyhow, Context, Result};
2116
use bindle::Invoice;
22-
pub use connection::BindleConnectionInfo;
2317
use futures::future;
18+
19+
use outbound_http::allowed_http_hosts::validate_allowed_http_hosts;
2420
use spin_manifest::{
2521
Application, ApplicationInformation, ApplicationOrigin, CoreComponent, ModuleSource,
2622
SpinVersion, WasmConfig,
2723
};
28-
use std::path::Path;
2924
use tracing::log;
25+
26+
use crate::bindle::{
27+
config::{RawAppManifest, RawComponentManifest},
28+
utils::{find_manifest, parcels_in_group},
29+
};
30+
pub use connection::BindleConnectionInfo;
3031
pub(crate) use utils::BindleReader;
3132
pub use utils::SPIN_MANIFEST_MEDIA_TYPE;
3233

@@ -142,7 +143,7 @@ async fn core(
142143
None => vec![],
143144
};
144145
let environment = raw.wasm.environment.unwrap_or_default();
145-
let allowed_http_hosts = parse_allowed_http_hosts(&raw.wasm.allowed_http_hosts)?;
146+
let allowed_http_hosts = raw.wasm.allowed_http_hosts.unwrap_or_default();
146147
let wasm = WasmConfig {
147148
environment,
148149
mounts,

crates/loader/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ mod assets;
1414
pub mod bindle;
1515
mod common;
1616
pub mod local;
17-
mod validation;
1817

1918
/// Load a Spin application configuration from a spin.toml manifest file.
2019
pub use local::from_file;

crates/loader/src/local/mod.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,20 @@ pub mod config;
1010
#[cfg(test)]
1111
mod tests;
1212

13+
use std::{path::Path, str::FromStr};
14+
1315
use anyhow::{anyhow, bail, Context, Result};
14-
use config::{RawAppInformation, RawAppManifest, RawAppManifestAnyVersion, RawComponentManifest};
1516
use futures::future;
17+
use outbound_http::allowed_http_hosts::validate_allowed_http_hosts;
1618
use path_absolutize::Absolutize;
1719
use spin_manifest::{
1820
Application, ApplicationInformation, ApplicationOrigin, CoreComponent, ModuleSource,
1921
SpinVersion, WasmConfig,
2022
};
21-
use std::{path::Path, str::FromStr};
2223
use tokio::{fs::File, io::AsyncReadExt};
2324

24-
use crate::{
25-
bindle::BindleConnectionInfo,
26-
validation::{parse_allowed_http_hosts, validate_allowed_http_hosts},
27-
};
25+
use crate::bindle::BindleConnectionInfo;
26+
use config::{RawAppInformation, RawAppManifest, RawAppManifestAnyVersion, RawComponentManifest};
2827

2928
/// Given the path to a spin.toml manifest file, prepare its assets locally and
3029
/// get a prepared application configuration consumable by a Spin execution context.
@@ -101,11 +100,9 @@ fn error_on_duplicate_ids(components: Vec<RawComponentManifest>) -> Result<()> {
101100
pub fn validate_raw_app_manifest(raw: &RawAppManifestAnyVersion) -> Result<()> {
102101
match raw {
103102
RawAppManifestAnyVersion::V1(raw) => {
104-
let _ = raw
105-
.components
103+
raw.components
106104
.iter()
107-
.map(|c| validate_allowed_http_hosts(&c.wasm.allowed_http_hosts))
108-
.collect::<Result<Vec<_>>>()?;
105+
.try_for_each(|c| validate_allowed_http_hosts(&c.wasm.allowed_http_hosts))?;
109106
}
110107
}
111108
Ok(())
@@ -223,7 +220,7 @@ async fn core(
223220
None => vec![],
224221
};
225222
let environment = raw.wasm.environment.unwrap_or_default();
226-
let allowed_http_hosts = parse_allowed_http_hosts(&raw.wasm.allowed_http_hosts)?;
223+
let allowed_http_hosts = raw.wasm.allowed_http_hosts.unwrap_or_default();
227224
let wasm = WasmConfig {
228225
environment,
229226
mounts,

crates/manifest/src/lib.rs

Lines changed: 1 addition & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -159,79 +159,6 @@ impl TryFrom<ApplicationTrigger> for RedisTriggerConfiguration {
159159
}
160160
}
161161

162-
/// An HTTP host allow-list.
163-
#[derive(Clone, Debug, Eq, PartialEq)]
164-
pub enum AllowedHttpHosts {
165-
/// All HTTP hosts are allowed (the "insecure:allow-all" value was present in the list)
166-
AllowAll,
167-
/// Only the specified hosts are allowed.
168-
AllowSpecific(Vec<AllowedHttpHost>),
169-
}
170-
171-
impl Default for AllowedHttpHosts {
172-
fn default() -> Self {
173-
Self::AllowSpecific(vec![])
174-
}
175-
}
176-
177-
impl AllowedHttpHosts {
178-
/// Tests whether the given URL is allowed according to the allow-list.
179-
pub fn allow(&self, url: &url::Url) -> bool {
180-
match self {
181-
Self::AllowAll => true,
182-
Self::AllowSpecific(hosts) => hosts.iter().any(|h| h.allow(url)),
183-
}
184-
}
185-
}
186-
187-
/// An HTTP host allow-list entry.
188-
#[derive(Clone, Debug, Default, Eq, PartialEq)]
189-
pub struct AllowedHttpHost {
190-
domain: String,
191-
port: Option<u16>,
192-
}
193-
194-
impl AllowedHttpHost {
195-
/// Creates a new allow-list entry.
196-
pub fn new(name: impl Into<String>, port: Option<u16>) -> Self {
197-
Self {
198-
domain: name.into(),
199-
port,
200-
}
201-
}
202-
203-
/// An allow-list entry that specifies a host and allows the default port.
204-
pub fn host(name: impl Into<String>) -> Self {
205-
Self {
206-
domain: name.into(),
207-
port: None,
208-
}
209-
}
210-
211-
/// An allow-list entry that specifies a host and port.
212-
pub fn host_and_port(name: impl Into<String>, port: u16) -> Self {
213-
Self {
214-
domain: name.into(),
215-
port: Some(port),
216-
}
217-
}
218-
219-
fn allow(&self, url: &url::Url) -> bool {
220-
(url.scheme() == "http" || url.scheme() == "https")
221-
&& self.domain == url.host_str().unwrap_or_default()
222-
&& self.port == url.port()
223-
}
224-
}
225-
226-
impl From<AllowedHttpHost> for String {
227-
fn from(allowed: AllowedHttpHost) -> Self {
228-
match allowed.port {
229-
Some(port) => format!("{}:{}", allowed.domain, port),
230-
None => allowed.domain,
231-
}
232-
}
233-
}
234-
235162
/// WebAssembly configuration.
236163
#[derive(Clone, Debug, Default)]
237164
pub struct WasmConfig {
@@ -240,7 +167,7 @@ pub struct WasmConfig {
240167
/// List of directory mounts that need to be mapped inside the WebAssembly module.
241168
pub mounts: Vec<DirectoryMount>,
242169
/// Optional list of HTTP hosts the component is allowed to connect.
243-
pub allowed_http_hosts: AllowedHttpHosts,
170+
pub allowed_http_hosts: Vec<String>,
244171
}
245172

246173
/// Directory mount for the assets of a component.

crates/outbound-http/Cargo.toml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@ doctest = false
99

1010
[dependencies]
1111
anyhow = "1.0"
12-
bytes = "1"
13-
futures = "0.3"
1412
http = "0.2"
15-
reqwest = { version = "0.11", default-features = true, features = [ "json", "blocking" ] }
16-
spin-engine = { path = "../engine" }
17-
spin-manifest = { path = "../manifest" }
13+
reqwest = "0.11"
14+
spin-app = { path = "../app" }
15+
spin-core = { path = "../core" }
1816
tracing = { version = "0.1", features = [ "log" ] }
1917
url = "2.2.1"
2018

2119
[dependencies.wit-bindgen-wasmtime]
2220
git = "https://github.com/bytecodealliance/wit-bindgen"
2321
rev = "cb871cfa1ee460b51eb1d144b175b9aab9c50aba"
24-
features = ["async"]
22+
features = ["async"]
23+

crates/loader/src/validation.rs renamed to crates/outbound-http/src/allowed_http_hosts.rs

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,71 @@
1-
#![deny(missing_docs)]
2-
31
use anyhow::{anyhow, Result};
42
use reqwest::Url;
5-
use spin_manifest::{AllowedHttpHost, AllowedHttpHosts};
3+
4+
const ALLOW_ALL_HOSTS: &str = "insecure:allow-all";
5+
6+
/// An HTTP host allow-list.
7+
#[derive(Clone, Debug, Eq, PartialEq)]
8+
pub enum AllowedHttpHosts {
9+
/// All HTTP hosts are allowed (the "insecure:allow-all" value was present in the list)
10+
AllowAll,
11+
/// Only the specified hosts are allowed.
12+
AllowSpecific(Vec<AllowedHttpHost>),
13+
}
14+
15+
impl Default for AllowedHttpHosts {
16+
fn default() -> Self {
17+
Self::AllowSpecific(vec![])
18+
}
19+
}
20+
21+
impl AllowedHttpHosts {
22+
/// Tests whether the given URL is allowed according to the allow-list.
23+
pub fn allow(&self, url: &url::Url) -> bool {
24+
match self {
25+
Self::AllowAll => true,
26+
Self::AllowSpecific(hosts) => hosts.iter().any(|h| h.allow(url)),
27+
}
28+
}
29+
}
30+
31+
/// An HTTP host allow-list entry.
32+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
33+
pub struct AllowedHttpHost {
34+
domain: String,
35+
port: Option<u16>,
36+
}
37+
38+
impl AllowedHttpHost {
39+
/// Creates a new allow-list entry.
40+
pub fn new(name: impl Into<String>, port: Option<u16>) -> Self {
41+
Self {
42+
domain: name.into(),
43+
port,
44+
}
45+
}
46+
47+
/// An allow-list entry that specifies a host and allows the default port.
48+
pub fn host(name: impl Into<String>) -> Self {
49+
Self {
50+
domain: name.into(),
51+
port: None,
52+
}
53+
}
54+
55+
/// An allow-list entry that specifies a host and port.
56+
pub fn host_and_port(name: impl Into<String>, port: u16) -> Self {
57+
Self {
58+
domain: name.into(),
59+
port: Some(port),
60+
}
61+
}
62+
63+
fn allow(&self, url: &url::Url) -> bool {
64+
(url.scheme() == "http" || url.scheme() == "https")
65+
&& self.domain == url.host_str().unwrap_or_default()
66+
&& self.port == url.port()
67+
}
68+
}
669

770
// Checks a list of allowed HTTP hosts is valid
871
pub fn validate_allowed_http_hosts(http_hosts: &Option<Vec<String>>) -> Result<()> {
@@ -14,10 +77,7 @@ pub fn parse_allowed_http_hosts(raw: &Option<Vec<String>>) -> Result<AllowedHttp
1477
match raw {
1578
None => Ok(AllowedHttpHosts::AllowSpecific(vec![])),
1679
Some(list) => {
17-
if list
18-
.iter()
19-
.any(|domain| domain == outbound_http::ALLOW_ALL_HOSTS)
20-
{
80+
if list.iter().any(|domain| domain == ALLOW_ALL_HOSTS) {
2181
Ok(AllowedHttpHosts::AllowAll)
2282
} else {
2383
let parse_results = list
Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
use anyhow::Result;
2-
use wit_bindgen_wasmtime::wasmtime::Linker;
32

4-
use spin_engine::{
5-
host_component::{HostComponent, HostComponentsStateHandle},
6-
RuntimeContext,
7-
};
8-
use spin_manifest::CoreComponent;
3+
use spin_app::DynamicHostComponent;
4+
use spin_core::{Data, HostComponent, Linker};
95

10-
use crate::OutboundHttp;
6+
use crate::{allowed_http_hosts::parse_allowed_http_hosts, OutboundHttp};
117

128
pub struct OutboundHttpComponent;
139

10+
pub const ALLOWED_HTTP_HOSTS_METADATA_KEY: &str = "allowed_http_hosts";
11+
1412
impl HostComponent for OutboundHttpComponent {
15-
type State = OutboundHttp;
13+
type Data = OutboundHttp;
1614

1715
fn add_to_linker<T: Send>(
18-
linker: &mut Linker<RuntimeContext<T>>,
19-
data_handle: HostComponentsStateHandle<Self::State>,
16+
linker: &mut Linker<T>,
17+
get: impl Fn(&mut Data<T>) -> &mut Self::Data + Send + Sync + Copy + 'static,
2018
) -> Result<()> {
21-
crate::add_to_linker(linker, move |ctx| data_handle.get_mut(ctx))?;
22-
Ok(())
19+
super::wasi_outbound_http::add_to_linker(linker, get)
20+
}
21+
22+
fn build_data(&self) -> Self::Data {
23+
Default::default()
2324
}
25+
}
2426

25-
fn build_state(&self, component: &CoreComponent) -> Result<Self::State> {
26-
Ok(OutboundHttp {
27-
allowed_hosts: component.wasm.allowed_http_hosts.clone(),
28-
})
27+
impl DynamicHostComponent for OutboundHttpComponent {
28+
fn update_data(
29+
&self,
30+
data: &mut Self::Data,
31+
component: &spin_app::AppComponent,
32+
) -> anyhow::Result<()> {
33+
let hosts = component
34+
.get_metadata(ALLOWED_HTTP_HOSTS_METADATA_KEY)
35+
.transpose()?;
36+
data.allowed_hosts = parse_allowed_http_hosts(&hosts)?;
37+
Ok(())
2938
}
3039
}

0 commit comments

Comments
 (0)