use std::path::PathBuf;
use hurl_core::ast::{Base64, Body, Bytes, File, Hex, Template};
use crate::http;
use crate::util::path::ContextDir;
use super::error::{RunnerError, RunnerErrorKind};
use super::json::eval_json_value;
use super::multiline::eval_multiline;
use super::template::eval_template;
use super::variable::VariableSet;
pub fn eval_body(
body: &Body,
variables: &VariableSet,
context_dir: &ContextDir,
) -> Result<http::Body, RunnerError> {
eval_bytes(&body.value, variables, context_dir)
}
pub fn eval_bytes(
bytes: &Bytes,
variables: &VariableSet,
context_dir: &ContextDir,
) -> Result<http::Body, RunnerError> {
match bytes {
Bytes::OnelineString(value) => {
let value = eval_template(value, variables)?;
Ok(http::Body::Text(value))
}
Bytes::MultilineString(value) => {
let value = eval_multiline(value, variables)?;
Ok(http::Body::Text(value))
}
Bytes::Xml(value) => Ok(http::Body::Text(value.clone())),
Bytes::Json(value) => {
let value = eval_json_value(value, variables, true)?;
Ok(http::Body::Text(value))
}
Bytes::Base64(Base64 { value, .. }) => Ok(http::Body::Binary(value.clone())),
Bytes::Hex(Hex { value, .. }) => Ok(http::Body::Binary(value.clone())),
Bytes::File(File { filename, .. }) => {
let value = eval_file(filename, variables, context_dir)?;
let filename = eval_template(filename, variables)?;
Ok(http::Body::File(value, filename))
}
}
}
pub fn eval_file(
filename: &Template,
variables: &VariableSet,
context_dir: &ContextDir,
) -> Result<Vec<u8>, RunnerError> {
let file = eval_template(filename, variables)?;
let path = PathBuf::from(file);
if !context_dir.is_access_allowed(&path) {
let kind = RunnerErrorKind::UnauthorizedFileAccess { path };
return Err(RunnerError::new(filename.source_info, kind, false));
}
let resolved_file = context_dir.resolved_path(&path);
match std::fs::read(resolved_file) {
Ok(value) => Ok(value),
Err(_) => {
let kind = RunnerErrorKind::FileReadAccess { path };
Err(RunnerError::new(filename.source_info, kind, false))
}
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use hurl_core::ast::{SourceInfo, TemplateElement, Whitespace};
use hurl_core::reader::Pos;
use hurl_core::types::ToSource;
use super::*;
#[test]
fn test_body_file() {
let whitespace = Whitespace {
value: String::from(" "),
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
};
let bytes = Bytes::File(File {
space0: whitespace.clone(),
filename: Template::new(
None,
vec![TemplateElement::String {
value: "tests/data.bin".to_string(),
source: "tests/data.bin".to_source(),
}],
SourceInfo::new(Pos::new(1, 7), Pos::new(1, 15)),
),
space1: whitespace,
});
let variables = VariableSet::new();
let current_dir = Path::new("/home");
let file_root = Path::new("");
let context_dir = ContextDir::new(current_dir, file_root);
assert_eq!(
eval_bytes(&bytes, &variables, &context_dir).unwrap(),
http::Body::File(b"Hello World!".to_vec(), "tests/data.bin".to_string())
);
}
#[test]
fn test_body_file_error() {
let whitespace = Whitespace {
value: String::from(" "),
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
};
let bytes = Bytes::File(File {
space0: whitespace.clone(),
filename: Template::new(
None,
vec![TemplateElement::String {
value: "data.bin".to_string(),
source: "data.bin".to_source(),
}],
SourceInfo::new(Pos::new(1, 7), Pos::new(1, 15)),
),
space1: whitespace,
});
let variables = VariableSet::new();
let current_dir = Path::new("/home");
let file_root = Path::new("file_root");
let context_dir = ContextDir::new(current_dir, file_root);
let error = eval_bytes(&bytes, &variables, &context_dir).err().unwrap();
assert_eq!(
error.kind,
RunnerErrorKind::FileReadAccess {
path: PathBuf::from("data.bin")
}
);
assert_eq!(
error.source_info,
SourceInfo::new(Pos::new(1, 7), Pos::new(1, 15))
);
}
}