Skip to content

Commit

Permalink
Require direct pass to get backend IP and port
Browse files Browse the repository at this point in the history
  • Loading branch information
ulyssa committed Jul 4, 2024
1 parent 10b6237 commit 270928a
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 7 deletions.
68 changes: 68 additions & 0 deletions lib/src/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::wiggle_abi::types::CacheOverrideTag;
use http::HeaderValue;

/// Optional override for response caching behavior.
#[derive(Clone, Debug, Default)]
pub enum CacheOverride {
/// Do not override the behavior specified in the origin response's cache control headers.
#[default]
None,
/// Do not cache the response to this request, regardless of the origin response's headers.
Pass,
/// Override particular cache control settings.
///
/// The origin response's cache control headers will be used for ttl and stale_while_revalidate if `None`.
Override {
ttl: Option<u32>,
stale_while_revalidate: Option<u32>,
pci: bool,
surrogate_key: Option<HeaderValue>,
},
}

impl CacheOverride {
pub fn is_pass(&self) -> bool {
if let Self::Pass = self {
true
} else {
false
}
}

/// Convert from the representation suitable for passing across the ABI boundary.
///
/// Returns `None` if the tag is not recognized. Depending on the tag, some of the values may be
/// ignored.
pub fn from_abi(
tag: u32,
ttl: u32,
swr: u32,
surrogate_key: Option<HeaderValue>,
) -> Option<Self> {
CacheOverrideTag::from_bits(tag).map(|tag| {
if tag.contains(CacheOverrideTag::PASS) {
return CacheOverride::Pass;
}
if tag.is_empty() && surrogate_key.is_none() {
return CacheOverride::None;
}
let ttl = if tag.contains(CacheOverrideTag::TTL) {
Some(ttl)
} else {
None
};
let stale_while_revalidate = if tag.contains(CacheOverrideTag::STALE_WHILE_REVALIDATE) {
Some(swr)
} else {
None
};
let pci = tag.contains(CacheOverrideTag::PCI);
CacheOverride::Override {
ttl,
stale_while_revalidate,
pci,
surrogate_key,
}
})
}
}
1 change: 1 addition & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

pub mod adapt;
pub mod body;
pub mod cache;
pub mod config;
pub mod error;
pub mod logging;
Expand Down
20 changes: 18 additions & 2 deletions lib/src/upstream.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
body::{Body, Chunk},
cache::CacheOverride,
config::Backend,
error::Error,
headers::filter_outgoing_headers,
Expand Down Expand Up @@ -112,6 +113,7 @@ impl Connection {

#[derive(Clone)]
pub struct ConnMetadata {
pub direct_pass: bool,
pub remote_addr: SocketAddr,
}

Expand Down Expand Up @@ -154,7 +156,10 @@ impl hyper::service::Service<Uri> for BackendConnector {
let tcp = connect_fut.await.map_err(Box::new)?;

let remote_addr = tcp.peer_addr()?;
let metadata = ConnMetadata { remote_addr };
let metadata = ConnMetadata {
direct_pass: false,
remote_addr,
};

let conn = if backend.uri.scheme_str() == Some("https") {
let mut config = if let Some(certed_key) = &backend.client_cert {
Expand Down Expand Up @@ -308,7 +313,13 @@ pub fn send_request(
builder.http2_only(true);
}

let basic_response = builder
let is_pass = req
.extensions()
.get::<CacheOverride>()
.map(CacheOverride::is_pass)
.unwrap_or_default();

let mut basic_response = builder
.set_host(false)
.http2_only(h2only)
.build(connector)
Expand All @@ -319,6 +330,11 @@ pub fn send_request(
e
})?;

if let Some(md) = basic_response.extensions_mut().get_mut::<ConnMetadata>() {
// This is used later to create similar behaviour between Compute and Viceroy.
md.direct_pass = is_pass;
}

if try_decompression
&& basic_response
.headers()
Expand Down
29 changes: 24 additions & 5 deletions lib/src/wiggle_abi/req_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use super::types::SendErrorDetail;
use super::SecretStoreError;
use crate::cache::CacheOverride;
use crate::config::ClientCertInfo;
use crate::secret_store::SecretLookup;

Expand Down Expand Up @@ -39,20 +40,24 @@ impl FastlyHttpReq for Session {
Ok((req_handle, body_handle))
}

#[allow(unused_variables)] // FIXME KTM 2020-06-25: Remove this directive once implemented.
fn cache_override_set(
&mut self,
memory: &mut GuestMemory<'_>,
_memory: &mut GuestMemory<'_>,
req_handle: RequestHandle,
tag: CacheOverrideTag,
ttl: u32,
stale_while_revalidate: u32,
) -> Result<(), Error> {
// For now, we ignore caching directives because we never cache anything
let overrides = CacheOverride::from_abi(u32::from(tag), ttl, stale_while_revalidate, None)
.ok_or(Error::InvalidArgument)?;

self.request_parts_mut(req_handle)?
.extensions
.insert(overrides);

Ok(())
}

#[allow(unused_variables)] // FIXME KTM 2020-06-25: Remove this directive once implemented.
fn cache_override_v2_set(
&mut self,
memory: &mut GuestMemory<'_>,
Expand All @@ -62,7 +67,21 @@ impl FastlyHttpReq for Session {
stale_while_revalidate: u32,
sk: GuestPtr<[u8]>,
) -> Result<(), Error> {
// For now, we ignore caching directives because we never cache anything
let sk = if sk.len() > 0 {
let sk = memory.as_slice(sk)?.ok_or(Error::SharedMemory)?;
let sk = HeaderValue::from_bytes(&sk).map_err(|_| Error::InvalidArgument)?;
Some(sk)
} else {
None
};

let overrides = CacheOverride::from_abi(u32::from(tag), ttl, stale_while_revalidate, sk)
.ok_or(Error::InvalidArgument)?;

self.request_parts_mut(req_handle)?
.extensions
.insert(overrides);

Ok(())
}

Expand Down
17 changes: 17 additions & 0 deletions lib/src/wiggle_abi/resp_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ impl FastlyHttpResp for Session {
.get::<upstream::ConnMetadata>()
.ok_or(Error::ValueAbsent)?;

if !md.direct_pass {
// Compute currently only returns this value when we are doing
// direct pass, so we skip returning a value here for now, even
// if we have one, so that guest code doesn't come to expect it
// during local testing.
return Err(Error::ValueAbsent);
}

match md.remote_addr.ip() {
IpAddr::V4(addr) => {
let octets = addr.octets();
Expand Down Expand Up @@ -268,6 +276,15 @@ impl FastlyHttpResp for Session {
.extensions
.get::<upstream::ConnMetadata>()
.ok_or(Error::ValueAbsent)?;

if !md.direct_pass {
// Compute currently only returns this value when we are doing
// direct pass, so we skip returning a value here for now, even
// if we have one, so that guest code doesn't come to expect it
// during local testing.
return Err(Error::ValueAbsent);
}

let port = md.remote_addr.port();
Ok(port)
}
Expand Down

0 comments on commit 270928a

Please sign in to comment.