Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: removing Clone derivation from Blueprint #1871

Closed
wants to merge 9 commits into from
6 changes: 3 additions & 3 deletions benches/impl_path_string_for_evaluation_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use once_cell::sync::Lazy;
use reqwest::{Client, Request};
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use tailcall::{
EnvIO, EvaluationContext, FileIO, HttpIO, InMemoryCache, PathString, RequestContext,
ArcString, EnvIO, EvaluationContext, FileIO, HttpIO, InMemoryCache, PathString, RequestContext,
ResolverContextLike, Response, Server, TargetRuntime, Upstream,
};

Expand Down Expand Up @@ -155,10 +155,10 @@ static TEST_HEADERS: Lazy<HeaderMap> = Lazy::new(|| {
map
});

static TEST_VARS: Lazy<BTreeMap<String, String>> = Lazy::new(|| {
static TEST_VARS: Lazy<BTreeMap<ArcString, ArcString>> = Lazy::new(|| {
let mut map = BTreeMap::new();

map.insert("existing".to_owned(), "var".to_owned());
map.insert("existing".into(), "var".into());

map
});
Expand Down
2 changes: 1 addition & 1 deletion src/cli/runtime/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl NativeHttp {
.http2_keep_alive_while_idle(upstream.keep_alive_while_idle)
.pool_idle_timeout(Some(Duration::from_secs(upstream.pool_idle_timeout)))
.pool_max_idle_per_host(upstream.pool_max_idle_per_host)
.user_agent(upstream.user_agent.clone());
.user_agent(upstream.user_agent.to_string());

// Add Http2 Prior Knowledge
if upstream.http2_only {
Expand Down
13 changes: 6 additions & 7 deletions src/cli/server/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@ impl Server {
pub async fn start(self) -> Result<()> {
let blueprint = Blueprint::try_from(&self.config_module).map_err(CLIError::from)?;
let server_config = Arc::new(
ServerConfig::new(
blueprint.clone(),
self.config_module.extensions.endpoint_set,
)
.await?,
ServerConfig::new(blueprint, self.config_module.extensions.endpoint_set).await?,
);

init_opentelemetry(blueprint.telemetry.clone(), &server_config.app_ctx.runtime)?;
init_opentelemetry(
server_config.blueprint.telemetry.clone(),
&server_config.app_ctx.runtime,
)?;

match blueprint.server.http.clone() {
match server_config.blueprint.server.http.clone() {
Http::HTTP2 { cert, key } => {
start_http_2(server_config, cert, key, self.server_up_sender).await
}
Expand Down
5 changes: 3 additions & 2 deletions src/cli/server/server_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::core::rest::{EndpointSet, Unchecked};
use crate::core::schema_extension::SchemaExtension;

pub struct ServerConfig {
pub blueprint: Blueprint,
pub blueprint: Arc<Blueprint>,
pub app_ctx: Arc<AppContext>,
}

Expand All @@ -37,7 +37,8 @@ impl ServerConfig {
rt.add_extensions(extensions);

let endpoints = endpoints.into_checked(&blueprint, rt.clone()).await?;
let app_context = Arc::new(AppContext::new(blueprint.clone(), rt, endpoints));
let app_context = Arc::new(AppContext::new(blueprint, rt, endpoints));
let blueprint = app_context.blueprint.clone();

Ok(Self { app_ctx: app_context, blueprint })
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/app_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::core::runtime::TargetRuntime;
pub struct AppContext {
pub schema: dynamic::Schema,
pub runtime: TargetRuntime,
pub blueprint: Blueprint,
pub blueprint: Arc<Blueprint>,
pub http_data_loaders: Arc<Vec<DataLoader<DataLoaderRequest, HttpDataLoader>>>,
pub gql_data_loaders: Arc<Vec<DataLoader<DataLoaderRequest, GraphqlDataLoader>>>,
pub grpc_data_loaders: Arc<Vec<DataLoader<grpc::DataLoaderRequest, GrpcDataLoader>>>,
Expand Down Expand Up @@ -118,7 +118,7 @@ impl AppContext {
AppContext {
schema,
runtime,
blueprint,
blueprint: Arc::new(blueprint),
http_data_loaders: Arc::new(http_data_loaders),
gql_data_loaders: Arc::new(gql_data_loaders),
grpc_data_loaders: Arc::new(grpc_data_loaders),
Expand Down
99 changes: 99 additions & 0 deletions src/core/arc_string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::sync::Arc;

use headers::HeaderValue;
use schemars::gen::SchemaGenerator;
use schemars::schema::Schema;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArcString(Arc<str>);

impl<'de> Deserialize<'de> for ArcString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer).map(ArcString::from)
}
}

impl Serialize for ArcString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_str().serialize(serializer)
}
}

impl Default for ArcString {
fn default() -> Self {
ArcString("".into())
}

Check warning on line 32 in src/core/arc_string.rs

View check run for this annotation

Codecov / codecov/patch

src/core/arc_string.rs#L30-L32

Added lines #L30 - L32 were not covered by tests
}

impl AsRef<str> for ArcString {
fn as_ref(&self) -> &str {
&self.0
}
}

impl From<&str> for ArcString {
fn from(s: &str) -> Self {
ArcString(s.into())
}
}

impl From<&String> for ArcString {
fn from(s: &String) -> Self {
ArcString(s.clone().into())
}
}

impl From<String> for ArcString {
fn from(s: String) -> Self {
ArcString(s.into())
}
}

impl From<ArcString> for Vec<u8> {
fn from(s: ArcString) -> Self {
s.as_str().as_bytes().to_vec()
}
}

impl TryFrom<ArcString> for HeaderValue {
type Error = <HeaderValue as TryFrom<String>>::Error;

fn try_from(s: ArcString) -> Result<Self, Self::Error> {
s.as_str().parse()
}
}

impl PartialEq<&str> for ArcString {
fn eq(&self, other: &&str) -> bool {
self.as_ref() == *other
}
}

impl schemars::JsonSchema for ArcString {
fn schema_name() -> String {
<String as schemars::JsonSchema>::schema_name()
}

Check warning on line 82 in src/core/arc_string.rs

View check run for this annotation

Codecov / codecov/patch

src/core/arc_string.rs#L80-L82

Added lines #L80 - L82 were not covered by tests

fn json_schema(gen: &mut SchemaGenerator) -> Schema {
<String as schemars::JsonSchema>::json_schema(gen)
}

Check warning on line 86 in src/core/arc_string.rs

View check run for this annotation

Codecov / codecov/patch

src/core/arc_string.rs#L84-L86

Added lines #L84 - L86 were not covered by tests
}

impl std::fmt::Display for ArcString {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.as_str().fmt(f)
}
}

impl ArcString {
pub fn as_str(&self) -> &str {
self.as_ref()
}
}
6 changes: 3 additions & 3 deletions src/core/auth/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Verify for BasicVerifier {

impl BasicVerifier {
pub fn new(options: blueprint::Basic) -> Self {
Self { verifier: Htpasswd::new_owned(&options.htpasswd) }
Self { verifier: Htpasswd::new_owned(options.htpasswd.as_ref()) }
}
}

Expand All @@ -58,7 +58,7 @@ testuser3:{SHA}Y2fEjdGT1W6nsLqtJbGUVeUp9e4=

impl blueprint::Basic {
pub fn test_value() -> Self {
Self { htpasswd: HTPASSWD_TEST.to_owned() }
Self { htpasswd: HTPASSWD_TEST.into() }
}
}

Expand Down Expand Up @@ -129,6 +129,6 @@ testuser3:{SHA}Y2fEjdGT1W6nsLqtJbGUVeUp9e4=

// Helper function for setting up the provider
fn setup_provider() -> BasicVerifier {
BasicVerifier::new(blueprint::Basic { htpasswd: HTPASSWD_TEST.to_owned() })
BasicVerifier::new(blueprint::Basic { htpasswd: HTPASSWD_TEST.into() })
}
}
2 changes: 1 addition & 1 deletion src/core/auth/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ mod tests {
// Helper function for setting up the auth context
async fn setup_auth_context() -> GlobalAuthContext {
let basic_provider =
BasicVerifier::new(blueprint::Basic { htpasswd: HTPASSWD_TEST.to_owned() });
BasicVerifier::new(blueprint::Basic { htpasswd: HTPASSWD_TEST.into() });
let jwt_options = blueprint::Jwt::test_value();
let jwt_provider = JwtVerifier::new(jwt_options);

Expand Down
2 changes: 1 addition & 1 deletion src/core/auth/jwt/jwks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ mod tests {
let data = jwks.decode(JWT_VALID_TOKEN_WITH_KID).unwrap();

assert!(matches!(data.aud, Some(OneOrMany::Vec(v)) if v == ["them"]));
assert!(matches!(data.iss, Some(v) if v == "me"));
assert!(matches!(data.iss, Some(v) if v.as_ref() == "me"));

assert!(matches!(
jwks.decode(JWT_VALID_TOKEN_NO_KID),
Expand Down
37 changes: 18 additions & 19 deletions src/core/auth/jwt/jwt_verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use headers::{Authorization, HeaderMapExt};
use serde::Deserialize;

use super::jwks::Jwks;
use crate::core::arc_string::ArcString;
use crate::core::auth::error::Error;
use crate::core::auth::verification::Verification;
use crate::core::auth::verify::Verify;
Expand All @@ -18,8 +19,8 @@ pub enum OneOrMany<T> {

#[derive(Debug, Default, Deserialize)]
pub struct JwtClaim {
pub aud: Option<OneOrMany<String>>,
pub iss: Option<String>,
pub aud: Option<OneOrMany<ArcString>>,
pub iss: Option<ArcString>,
}

pub struct JwtVerifier {
Expand Down Expand Up @@ -184,10 +185,8 @@ pub mod tests {

assert_eq!(valid, Verification::succeed());

let jwt_options = blueprint::Jwt {
issuer: Some("me".to_owned()),
..blueprint::Jwt::test_value()
};
let jwt_options =
blueprint::Jwt { issuer: Some("me".into()), ..blueprint::Jwt::test_value() };
let jwt_provider = JwtVerifier::new(jwt_options);

let valid = jwt_provider
Expand All @@ -197,7 +196,7 @@ pub mod tests {
assert_eq!(valid, Verification::succeed());

let jwt_options = blueprint::Jwt {
issuer: Some("another".to_owned()),
issuer: Some("another".into()),
..blueprint::Jwt::test_value()
};
let jwt_provider = JwtVerifier::new(jwt_options);
Expand All @@ -221,7 +220,7 @@ pub mod tests {
assert_eq!(valid, Verification::succeed());

let jwt_options = blueprint::Jwt {
audiences: HashSet::from_iter(["them".to_string()]),
audiences: HashSet::from_iter(["them".into()]),
..blueprint::Jwt::test_value()
};
let jwt_provider = JwtVerifier::new(jwt_options);
Expand All @@ -233,7 +232,7 @@ pub mod tests {
assert_eq!(valid, Verification::succeed());

let jwt_options = blueprint::Jwt {
audiences: HashSet::from_iter(["anothem".to_string()]),
audiences: HashSet::from_iter(["anothem".into()]),
..blueprint::Jwt::test_value()
};
let jwt_provider = JwtVerifier::new(jwt_options);
Expand All @@ -256,23 +255,23 @@ pub mod tests {

assert!(validate_iss(&options, &claims));

claims.iss = Some("iss".to_owned());
claims.iss = Some("iss".into());

assert!(validate_iss(&options, &claims));
}

#[test]
fn validate_iss_defined() {
let options = Jwt { issuer: Some("iss".to_owned()), ..Jwt::test_value() };
let options = Jwt { issuer: Some("iss".into()), ..Jwt::test_value() };
let mut claims = JwtClaim::default();

assert!(!validate_iss(&options, &claims));

claims.iss = Some("wrong".to_owned());
claims.iss = Some("wrong".into());

assert!(!validate_iss(&options, &claims));

claims.iss = Some("iss".to_owned());
claims.iss = Some("iss".into());

assert!(validate_iss(&options, &claims));
}
Expand All @@ -290,29 +289,29 @@ pub mod tests {
let mut claims = JwtClaim::default();
assert!(validate_aud(&options, &claims));

claims.aud = Some(OneOrMany::One("aud".to_owned()));
claims.aud = Some(OneOrMany::One("aud".into()));
assert!(validate_aud(&options, &claims));

claims.aud = Some(OneOrMany::Vec(vec!["aud1".to_owned(), "aud2".to_owned()]));
claims.aud = Some(OneOrMany::Vec(vec!["aud1".into(), "aud2".into()]));
assert!(validate_aud(&options, &claims));
}

#[test]
fn validate_aud_defined() {
let options = Jwt {
audiences: HashSet::from_iter(["aud1".to_owned(), "aud2".to_owned()]),
audiences: HashSet::from_iter(["aud1".into(), "aud2".into()]),
..Jwt::test_value()
};
let mut claims = JwtClaim::default();
assert!(!validate_aud(&options, &claims));

claims.aud = Some(OneOrMany::One("wrong".to_owned()));
claims.aud = Some(OneOrMany::One("wrong".into()));
assert!(!validate_aud(&options, &claims));

claims.aud = Some(OneOrMany::One("aud1".to_owned()));
claims.aud = Some(OneOrMany::One("aud1".into()));
assert!(validate_aud(&options, &claims));

claims.aud = Some(OneOrMany::Vec(vec!["aud1".to_owned(), "aud5".to_owned()]));
claims.aud = Some(OneOrMany::Vec(vec!["aud1".into(), "aud5".into()]));
assert!(validate_aud(&options, &claims));
}
}
Expand Down
9 changes: 5 additions & 4 deletions src/core/blueprint/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ use std::fmt::Debug;

use jsonwebtoken::jwk::JwkSet;

use crate::core::arc_string::ArcString;
use crate::core::config::ConfigModule;
use crate::core::valid::Valid;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Basic {
pub htpasswd: String,
pub htpasswd: ArcString,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Jwt {
pub issuer: Option<String>,
pub audiences: HashSet<String>,
pub issuer: Option<ArcString>,
pub audiences: HashSet<ArcString>,
pub optional_kid: bool,
pub jwks: JwkSet,
}
Expand All @@ -36,7 +37,7 @@ impl Auth {
pub fn make(config_module: &ConfigModule) -> Valid<Option<Auth>, String> {
let htpasswd = config_module.extensions.htpasswd.iter().map(|htpasswd| {
Auth::Provider(Provider::Basic(Basic {
htpasswd: htpasswd.content.clone(),
htpasswd: htpasswd.content.as_str().into(),
}))
});

Expand Down