Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog.d/http_client_vrl_compilation_errors.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The `http_client` source now fails to start if VRL compilation errors occur in `query` parameters when
type is set to `vrl`, instead of silently logging a warning and continuing with invalid expressions.
This prevents unexpected behavior where malformed VRL would be sent as literal strings in HTTP requests.

authors: thomasqueirozb
46 changes: 27 additions & 19 deletions src/sources/http_client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,17 +214,19 @@ pub struct Query {
}

impl Query {
pub fn new(params: &HashMap<String, QueryParameterValue>) -> Self {
pub fn new(params: &HashMap<String, QueryParameterValue>) -> Result<Self, sources::BuildError> {
let functions = vrl::stdlib::all()
.into_iter()
.chain(vector_lib::enrichment::vrl_functions())
.chain(vector_vrl_functions::all())
.collect::<Vec<_>>();

let compiled: HashMap<String, CompiledQueryParameterValue> = params
.iter()
.map(|(k, v)| (k.clone(), Self::compile_param(v, &functions)))
.collect();
let mut compiled: HashMap<String, CompiledQueryParameterValue> = HashMap::new();

for (k, v) in params.iter() {
let compiled_param = Self::compile_param(v, &functions)?;
compiled.insert(k.clone(), compiled_param);
}

let has_vrl = compiled.values().any(|compiled| match compiled {
CompiledQueryParameterValue::SingleParam(param) => param.program.is_some(),
Expand All @@ -233,14 +235,17 @@ impl Query {
}
});

Query {
Ok(Query {
original: params.clone(),
compiled,
has_vrl,
}
})
}

fn compile_value(param: &ParameterValue, functions: &[Box<dyn Function>]) -> CompiledParam {
fn compile_value(
param: &ParameterValue,
functions: &[Box<dyn Function>],
) -> Result<CompiledParam, sources::BuildError> {
let program = if param.is_vrl() {
let state = TypeState::default();
let config = CompileConfig::default();
Expand All @@ -256,34 +261,37 @@ impl Query {
}
Err(diagnostics) => {
let error = format_vrl_diagnostics(param.value(), diagnostics);
warn!(message = "VRL compilation failed.", %error);
None
return Err(sources::BuildError::VrlCompilationError {
message: format!("VRL compilation failed: {}", error),
});
}
}
} else {
None
};

CompiledParam {
Ok(CompiledParam {
value: param.value().to_string(),
program,
}
})
}

fn compile_param(
value: &QueryParameterValue,
functions: &[Box<dyn Function>],
) -> CompiledQueryParameterValue {
) -> Result<CompiledQueryParameterValue, sources::BuildError> {
match value {
QueryParameterValue::SingleParam(param) => CompiledQueryParameterValue::SingleParam(
Box::new(Self::compile_value(param, functions)),
),
QueryParameterValue::SingleParam(param) => {
Ok(CompiledQueryParameterValue::SingleParam(Box::new(
Self::compile_value(param, functions)?,
)))
}
QueryParameterValue::MultiParams(params) => {
let compiled = params
.iter()
.map(|p| Self::compile_value(p, functions))
.collect();
CompiledQueryParameterValue::MultiParams(compiled)
.collect::<Result<Vec<_>, _>>()?;
Ok(CompiledQueryParameterValue::MultiParams(compiled))
}
}
}
Expand All @@ -293,7 +301,7 @@ impl Query {
#[typetag::serde(name = "http_client")]
impl SourceConfig for HttpClientConfig {
async fn build(&self, cx: SourceContext) -> crate::Result<sources::Source> {
let query = Query::new(&self.query.clone());
let query = Query::new(&self.query.clone())?;

// Build the base URLs
let endpoints = [self.endpoint.clone()];
Expand Down
4 changes: 3 additions & 1 deletion src/sources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ pub use vector_lib::source::Source;
#[allow(dead_code)] // Easier than listing out all the features that use this
/// Common build errors
#[derive(Debug, Snafu)]
enum BuildError {
pub enum BuildError {
#[snafu(display("URI parse error: {}", source))]
UriParseError { source: ::http::uri::InvalidUri },
#[snafu(display("VRL compilation error: {}", message))]
VrlCompilationError { message: String },
}
Loading