mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-23 00:44:55 +03:00
Use Template for filename type
This commit is contained in:
parent
4511e37e06
commit
6ac325d879
@ -2,6 +2,10 @@ POST http://localhost:8000/post-file
|
||||
file,data.bin;
|
||||
HTTP 200
|
||||
|
||||
POST http://localhost:8000/post-file
|
||||
file,{{filename}};
|
||||
HTTP 200
|
||||
|
||||
POST http://localhost:8000/post-file
|
||||
file,post_file_with\ space;
|
||||
HTTP 200
|
||||
|
@ -1,3 +1,3 @@
|
||||
Set-StrictMode -Version latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
hurl tests_ok/post_file.hurl --verbose
|
||||
hurl tests_ok/post_file.hurl --variable filename=data.bin --verbose
|
||||
|
@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
hurl tests_ok/post_file.hurl --verbose
|
||||
hurl tests_ok/post_file.hurl --variable filename=data.bin --verbose
|
||||
|
@ -99,7 +99,7 @@ fn log_request(request: Request) {
|
||||
};
|
||||
eprintln!(
|
||||
"\r{}: {}{}",
|
||||
file_param.key, file_param.value.filename.value, content_type
|
||||
file_param.key, file_param.value.filename, content_type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -58,16 +58,21 @@ pub fn eval_bytes(
|
||||
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, context_dir)?;
|
||||
Ok(http::Body::File(value, filename.value.clone()))
|
||||
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: &Filename, context_dir: &ContextDir) -> Result<Vec<u8>, Error> {
|
||||
pub fn eval_file(
|
||||
filename: &Template,
|
||||
variables: &HashMap<String, Value>,
|
||||
context_dir: &ContextDir,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let file = eval_template(filename, variables)?;
|
||||
// In order not to leak any private date, we check that the user provided file
|
||||
// is a child of the context directory.
|
||||
let file = filename.value.clone();
|
||||
if !context_dir.is_access_allowed(&file) {
|
||||
let inner = RunnerError::UnauthorizedFileAccess {
|
||||
path: PathBuf::from(file),
|
||||
@ -100,9 +105,13 @@ mod tests {
|
||||
|
||||
let bytes = Bytes::File(File {
|
||||
space0: whitespace.clone(),
|
||||
filename: Filename {
|
||||
value: String::from("tests/data.bin"),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 15)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "tests/data.bin".to_string(),
|
||||
encoded: "tests/data.bin".to_string(),
|
||||
}],
|
||||
},
|
||||
space1: whitespace,
|
||||
});
|
||||
@ -127,9 +136,13 @@ mod tests {
|
||||
|
||||
let bytes = Bytes::File(File {
|
||||
space0: whitespace.clone(),
|
||||
filename: Filename {
|
||||
value: String::from("data.bin"),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 15)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "data.bin".to_string(),
|
||||
encoded: "data.bin".to_string(),
|
||||
}],
|
||||
},
|
||||
space1: whitespace,
|
||||
});
|
||||
|
@ -52,37 +52,44 @@ pub fn eval_file_param(
|
||||
variables: &HashMap<String, Value>,
|
||||
) -> Result<http::FileParam, Error> {
|
||||
let name = eval_template(&file_param.key, variables)?;
|
||||
let filename = file_param.value.filename.clone();
|
||||
let data = eval_file(&filename, context_dir)?;
|
||||
let content_type = file_value_content_type(&file_param.value);
|
||||
let filename = eval_template(&file_param.value.filename, variables)?;
|
||||
let data = eval_file(&file_param.value.filename, variables, context_dir)?;
|
||||
let content_type = file_value_content_type(&file_param.value, variables)?;
|
||||
Ok(http::FileParam {
|
||||
name,
|
||||
filename: filename.value,
|
||||
filename,
|
||||
data,
|
||||
content_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn file_value_content_type(file_value: &FileValue) -> String {
|
||||
match file_value.content_type.clone() {
|
||||
None => match Path::new(file_value.filename.value.as_str())
|
||||
.extension()
|
||||
.and_then(OsStr::to_str)
|
||||
{
|
||||
Some("gif") => "image/gif".to_string(),
|
||||
Some("jpg") => "image/jpeg".to_string(),
|
||||
Some("jpeg") => "image/jpeg".to_string(),
|
||||
Some("png") => "image/png".to_string(),
|
||||
Some("svg") => "image/svg+xml".to_string(),
|
||||
Some("txt") => "text/plain".to_string(),
|
||||
Some("htm") => "text/html".to_string(),
|
||||
Some("html") => "text/html".to_string(),
|
||||
Some("pdf") => "application/pdf".to_string(),
|
||||
Some("xml") => "application/xml".to_string(),
|
||||
_ => "application/octet-stream".to_string(),
|
||||
},
|
||||
pub fn file_value_content_type(
|
||||
file_value: &FileValue,
|
||||
variables: &HashMap<String, Value>,
|
||||
) -> Result<String, Error> {
|
||||
let value = match file_value.content_type.clone() {
|
||||
None => {
|
||||
let value = eval_template(&file_value.filename, variables)?;
|
||||
match Path::new(value.as_str())
|
||||
.extension()
|
||||
.and_then(OsStr::to_str)
|
||||
{
|
||||
Some("gif") => "image/gif".to_string(),
|
||||
Some("jpg") => "image/jpeg".to_string(),
|
||||
Some("jpeg") => "image/jpeg".to_string(),
|
||||
Some("png") => "image/png".to_string(),
|
||||
Some("svg") => "image/svg+xml".to_string(),
|
||||
Some("txt") => "text/plain".to_string(),
|
||||
Some("htm") => "text/html".to_string(),
|
||||
Some("html") => "text/html".to_string(),
|
||||
Some("pdf") => "application/pdf".to_string(),
|
||||
Some("xml") => "application/xml".to_string(),
|
||||
_ => "application/octet-stream".to_string(),
|
||||
}
|
||||
}
|
||||
Some(content_type) => content_type,
|
||||
}
|
||||
};
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -125,9 +132,13 @@ mod tests {
|
||||
space2: whitespace(),
|
||||
value: FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Filename {
|
||||
value: "hello.txt".to_string(),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello.txt".to_string(),
|
||||
encoded: "hello.txt".to_string(),
|
||||
}],
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
@ -152,59 +163,92 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
pub fn test_file_value_content_type() {
|
||||
let variables = HashMap::default();
|
||||
assert_eq!(
|
||||
file_value_content_type(&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Filename {
|
||||
value: "hello.txt".to_string(),
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
file_value_content_type(
|
||||
&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello.txt".to_string(),
|
||||
encoded: "hello.txt".to_string()
|
||||
}],
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: None,
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: None,
|
||||
}),
|
||||
&variables
|
||||
)
|
||||
.unwrap(),
|
||||
"text/plain".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
file_value_content_type(&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Filename {
|
||||
value: "hello.html".to_string(),
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
file_value_content_type(
|
||||
&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello.html".to_string(),
|
||||
encoded: "hello.html".to_string()
|
||||
}],
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: None,
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: None,
|
||||
}),
|
||||
&variables
|
||||
)
|
||||
.unwrap(),
|
||||
"text/html".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
file_value_content_type(&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Filename {
|
||||
value: "hello.txt".to_string(),
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
file_value_content_type(
|
||||
&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello.txt".to_string(),
|
||||
encoded: "hello.txt".to_string()
|
||||
}],
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: Some("text/html".to_string()),
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: Some("text/html".to_string()),
|
||||
}),
|
||||
&variables
|
||||
)
|
||||
.unwrap(),
|
||||
"text/html".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
file_value_content_type(&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Filename {
|
||||
value: "hello".to_string(),
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
file_value_content_type(
|
||||
&FileValue {
|
||||
space0: whitespace(),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello".to_string(),
|
||||
encoded: "hello".to_string()
|
||||
}],
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: None,
|
||||
},
|
||||
space1: whitespace(),
|
||||
space2: whitespace(),
|
||||
content_type: None,
|
||||
}),
|
||||
&variables
|
||||
)
|
||||
.unwrap(),
|
||||
"application/octet-stream".to_string()
|
||||
);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use hurl_core::ast::{
|
||||
|
||||
use crate::http::{IpResolve, RequestedHttpVersion};
|
||||
use crate::runner::template::{eval_expression, eval_template};
|
||||
use crate::runner::{template, Error, Number, RunnerError, RunnerOptions, Value};
|
||||
use crate::runner::{Error, Number, RunnerError, RunnerOptions, Value};
|
||||
use crate::util::logger::{Logger, Verbosity};
|
||||
|
||||
/// Returns a new [`RunnerOptions`] based on the `entry` optional Options section
|
||||
@ -54,13 +54,16 @@ pub fn get_entry_options(
|
||||
runner_options.aws_sigv4 = Some(value)
|
||||
}
|
||||
OptionKind::CaCertificate(filename) => {
|
||||
runner_options.cacert_file = Some(filename.value.clone())
|
||||
let value = eval_template(filename, variables)?;
|
||||
runner_options.cacert_file = Some(value)
|
||||
}
|
||||
OptionKind::ClientCert(filename) => {
|
||||
runner_options.client_cert_file = Some(filename.value.clone())
|
||||
let value = eval_template(filename, variables)?;
|
||||
runner_options.client_cert_file = Some(value)
|
||||
}
|
||||
OptionKind::ClientKey(filename) => {
|
||||
runner_options.client_key_file = Some(filename.value.clone())
|
||||
let value = eval_template(filename, variables)?;
|
||||
runner_options.client_key_file = Some(value)
|
||||
}
|
||||
OptionKind::Compressed(value) => {
|
||||
let value = eval_boolean_option(value, variables)?;
|
||||
@ -157,7 +160,8 @@ pub fn get_entry_options(
|
||||
runner_options.max_redirect = Some(value as usize)
|
||||
}
|
||||
OptionKind::Output(filename) => {
|
||||
runner_options.output = Some(filename.value.clone())
|
||||
let value = eval_template(filename, variables)?;
|
||||
runner_options.output = Some(value)
|
||||
}
|
||||
OptionKind::PathAsIs(value) => {
|
||||
let value = eval_boolean_option(value, variables)?;
|
||||
@ -346,7 +350,7 @@ fn eval_variable_value(
|
||||
VariableValue::Bool(v) => Ok(Value::Bool(*v)),
|
||||
VariableValue::Number(v) => Ok(eval_number(v)),
|
||||
VariableValue::String(template) => {
|
||||
let s = template::eval_template(template, variables)?;
|
||||
let s = eval_template(template, variables)?;
|
||||
Ok(Value::String(s))
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ pub fn eval_predicate_value(
|
||||
PredicateValue::Null => Ok(Value::Null),
|
||||
PredicateValue::Number(value) => Ok(Value::Number(eval_number(value))),
|
||||
PredicateValue::File(value) => {
|
||||
let value = eval_file(&value.filename, context_dir)?;
|
||||
let value = eval_file(&value.filename, variables, context_dir)?;
|
||||
Ok(Value::Bytes(value))
|
||||
}
|
||||
PredicateValue::Hex(value) => Ok(Value::Bytes(value.value.clone())),
|
||||
|
@ -267,7 +267,7 @@ pub struct FileParam {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct FileValue {
|
||||
pub space0: Whitespace,
|
||||
pub filename: Filename,
|
||||
pub filename: Template,
|
||||
pub space1: Whitespace,
|
||||
pub space2: Whitespace,
|
||||
pub content_type: Option<String>,
|
||||
@ -561,7 +561,7 @@ pub struct Base64 {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct File {
|
||||
pub space0: Whitespace,
|
||||
pub filename: Filename,
|
||||
pub filename: Template,
|
||||
pub space1: Whitespace,
|
||||
}
|
||||
|
||||
@ -599,12 +599,6 @@ pub struct Whitespace {
|
||||
pub source_info: SourceInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Filename {
|
||||
pub value: String,
|
||||
pub source_info: SourceInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Number {
|
||||
Float(Float),
|
||||
@ -718,9 +712,9 @@ pub struct EntryOption {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum OptionKind {
|
||||
AwsSigV4(Template),
|
||||
CaCertificate(Filename),
|
||||
ClientCert(Filename),
|
||||
ClientKey(Filename),
|
||||
CaCertificate(Template),
|
||||
ClientCert(Template),
|
||||
ClientKey(Template),
|
||||
Compressed(BooleanOption),
|
||||
ConnectTo(Template),
|
||||
Delay(NaturalOption),
|
||||
@ -733,7 +727,7 @@ pub enum OptionKind {
|
||||
IpV6(BooleanOption),
|
||||
FollowLocation(BooleanOption),
|
||||
MaxRedirect(NaturalOption),
|
||||
Output(Filename),
|
||||
Output(Template),
|
||||
PathAsIs(BooleanOption),
|
||||
Proxy(Template),
|
||||
Resolve(Template),
|
||||
@ -780,9 +774,9 @@ impl OptionKind {
|
||||
pub fn value_as_str(&self) -> String {
|
||||
match self {
|
||||
OptionKind::AwsSigV4(value) => value.to_string(),
|
||||
OptionKind::CaCertificate(filename) => filename.value.clone(),
|
||||
OptionKind::ClientCert(filename) => filename.value.clone(),
|
||||
OptionKind::ClientKey(filename) => filename.value.clone(),
|
||||
OptionKind::CaCertificate(filename) => filename.to_string(),
|
||||
OptionKind::ClientCert(filename) => filename.to_string(),
|
||||
OptionKind::ClientKey(filename) => filename.to_string(),
|
||||
OptionKind::Compressed(value) => value.to_string(),
|
||||
OptionKind::ConnectTo(value) => value.to_string(),
|
||||
OptionKind::Delay(value) => value.to_string(),
|
||||
@ -795,7 +789,7 @@ impl OptionKind {
|
||||
OptionKind::IpV4(value) => value.to_string(),
|
||||
OptionKind::IpV6(value) => value.to_string(),
|
||||
OptionKind::MaxRedirect(value) => value.to_string(),
|
||||
OptionKind::Output(filename) => filename.value.to_string(),
|
||||
OptionKind::Output(filename) => filename.to_string(),
|
||||
OptionKind::PathAsIs(value) => value.to_string(),
|
||||
OptionKind::Proxy(value) => value.to_string(),
|
||||
OptionKind::Resolve(value) => value.to_string(),
|
||||
|
@ -308,9 +308,9 @@ impl HtmlFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_filename(&mut self, filename: &Filename) {
|
||||
fn fmt_filename(&mut self, filename: &Template) {
|
||||
self.fmt_span_open("filename");
|
||||
let s = filename.value.replace(' ', "\\ ");
|
||||
let s = filename.to_string().replace(' ', "\\ ");
|
||||
self.buffer.push_str(s.as_str());
|
||||
self.fmt_span_close();
|
||||
}
|
||||
|
@ -17,30 +17,138 @@
|
||||
*/
|
||||
use crate::ast::*;
|
||||
use crate::parser::error::*;
|
||||
use crate::parser::primitives::try_literal;
|
||||
use crate::parser::reader::Reader;
|
||||
use crate::parser::ParseResult;
|
||||
use crate::parser::template::template;
|
||||
use crate::parser::{string, ParseResult};
|
||||
|
||||
pub fn parse(reader: &mut Reader) -> ParseResult<Filename> {
|
||||
// This is an absolute file
|
||||
// that you have to write with a relative name
|
||||
// default root_dir is the hurl directory
|
||||
pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
||||
let start = reader.state;
|
||||
let s = reader.read_while_escaping(|c| {
|
||||
c.is_alphanumeric() || *c == '.' || *c == '/' || *c == '_' || *c == '-' || *c == ':'
|
||||
});
|
||||
if s.is_empty() {
|
||||
return Err(Error::new(start.pos, false, ParseError::Filename));
|
||||
|
||||
let mut elements = vec![];
|
||||
loop {
|
||||
match template(reader) {
|
||||
Ok(expr) => {
|
||||
let element = TemplateElement::Expression(expr);
|
||||
elements.push(element);
|
||||
}
|
||||
Err(e) => {
|
||||
if e.recoverable {
|
||||
let value = filename_content(reader)?;
|
||||
if value.is_empty() {
|
||||
break;
|
||||
}
|
||||
let encoded: String = reader.buffer[start.cursor..reader.state.cursor]
|
||||
.iter()
|
||||
.collect();
|
||||
let element = TemplateElement::String { value, encoded };
|
||||
elements.push(element);
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if elements.is_empty() {
|
||||
let inner = ParseError::Filename;
|
||||
return Err(Error::new(start.pos, false, inner));
|
||||
}
|
||||
if let Some(TemplateElement::String { encoded, .. }) = elements.first() {
|
||||
if encoded.starts_with('[') {
|
||||
let inner = ParseError::Expecting {
|
||||
value: "filename".to_string(),
|
||||
};
|
||||
return Err(Error::new(start.pos, false, inner));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Filename {
|
||||
value: s,
|
||||
let end = reader.state;
|
||||
Ok(Template {
|
||||
delimiter: None,
|
||||
elements,
|
||||
source_info: SourceInfo {
|
||||
start: start.pos,
|
||||
end: reader.state.pos,
|
||||
end: end.pos,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn filename_content(reader: &mut Reader) -> ParseResult<String> {
|
||||
let mut s = String::new();
|
||||
loop {
|
||||
match filename_escaped_char(reader) {
|
||||
Ok(c) => {
|
||||
s.push(c);
|
||||
}
|
||||
Err(e) => {
|
||||
if e.recoverable {
|
||||
let s2 = filename_text(reader);
|
||||
if s2.is_empty() {
|
||||
break;
|
||||
} else {
|
||||
s.push_str(&s2);
|
||||
}
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
fn filename_text(reader: &mut Reader) -> String {
|
||||
let mut s = String::new();
|
||||
loop {
|
||||
let save = reader.state;
|
||||
match reader.read() {
|
||||
None => break,
|
||||
Some(c) => {
|
||||
if c.is_alphanumeric()
|
||||
|| c == '_'
|
||||
|| c == '-'
|
||||
|| c == '.'
|
||||
|| c == '['
|
||||
|| c == ']'
|
||||
|| c == '@'
|
||||
|| c == '$'
|
||||
|| c == '/'
|
||||
|| c == ':'
|
||||
{
|
||||
s.push(c);
|
||||
} else {
|
||||
reader.state = save;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
fn filename_escaped_char(reader: &mut Reader) -> ParseResult<char> {
|
||||
try_literal("\\", reader)?;
|
||||
let start = reader.state;
|
||||
match reader.read() {
|
||||
Some(';') => Ok(';'),
|
||||
Some('#') => Ok('#'),
|
||||
Some('[') => Ok('['),
|
||||
Some(' ') => Ok(' '),
|
||||
Some(']') => Ok(']'),
|
||||
Some(':') => Ok(':'),
|
||||
Some('\\') => Ok('\\'),
|
||||
Some('/') => Ok('/'),
|
||||
Some('b') => Ok('\x08'),
|
||||
Some('f') => Ok('\x0c'),
|
||||
Some('n') => Ok('\n'),
|
||||
Some('r') => Ok('\r'),
|
||||
Some('t') => Ok('\t'),
|
||||
Some('u') => string::unicode(reader),
|
||||
_ => Err(Error::new(start.pos, false, ParseError::EscapeChar)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -51,8 +159,12 @@ mod tests {
|
||||
let mut reader = Reader::new("data/data.bin");
|
||||
assert_eq!(
|
||||
parse(&mut reader).unwrap(),
|
||||
Filename {
|
||||
value: String::from("data/data.bin"),
|
||||
Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "data/data.bin".to_string(),
|
||||
encoded: "data/data.bin".to_string()
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 14)),
|
||||
}
|
||||
);
|
||||
@ -61,8 +173,13 @@ mod tests {
|
||||
let mut reader = Reader::new("data.bin");
|
||||
assert_eq!(
|
||||
parse(&mut reader).unwrap(),
|
||||
Filename {
|
||||
value: String::from("data.bin"),
|
||||
Template {
|
||||
//value: String::from("data.bin"),
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "data.bin".to_string(),
|
||||
encoded: "data.bin".to_string()
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 9)),
|
||||
}
|
||||
);
|
||||
@ -74,8 +191,12 @@ mod tests {
|
||||
let mut reader = Reader::new("file\\ with\\ spaces");
|
||||
assert_eq!(
|
||||
parse(&mut reader).unwrap(),
|
||||
Filename {
|
||||
value: String::from("file with spaces"),
|
||||
Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "file with spaces".to_string(),
|
||||
encoded: "file\\ with\\ spaces".to_string()
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 19)),
|
||||
}
|
||||
);
|
||||
|
@ -453,8 +453,12 @@ mod tests {
|
||||
end: Pos { line: 1, column: 9 },
|
||||
},
|
||||
},
|
||||
kind: OptionKind::CaCertificate(Filename {
|
||||
value: "/home/foo/cert.pem".to_string(),
|
||||
kind: OptionKind::CaCertificate(Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "/home/foo/cert.pem".to_string(),
|
||||
encoded: "/home/foo/cert.pem".to_string()
|
||||
}],
|
||||
source_info: SourceInfo {
|
||||
start: Pos { line: 1, column: 9 },
|
||||
end: Pos {
|
||||
|
@ -904,8 +904,12 @@ mod tests {
|
||||
value: String::new(),
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
|
||||
},
|
||||
filename: Filename {
|
||||
value: String::from("data.xml"),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: String::from("data.xml"),
|
||||
encoded: String::from("data.xml"),
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 14)),
|
||||
},
|
||||
space1: Whitespace {
|
||||
@ -923,8 +927,12 @@ mod tests {
|
||||
value: String::from(" "),
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
|
||||
},
|
||||
filename: Filename {
|
||||
value: String::from("filename1"),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: String::from("filename1"),
|
||||
encoded: String::from("filename1"),
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 16)),
|
||||
},
|
||||
space1: Whitespace {
|
||||
@ -942,8 +950,12 @@ mod tests {
|
||||
value: String::from(" "),
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
|
||||
},
|
||||
filename: Filename {
|
||||
value: String::from("tmp/filename1"),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: String::from("tmp/filename1"),
|
||||
encoded: String::from("tmp/filename1"),
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 20)),
|
||||
},
|
||||
space1: Whitespace {
|
||||
@ -961,8 +973,12 @@ mod tests {
|
||||
value: String::from(" "),
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
|
||||
},
|
||||
filename: Filename {
|
||||
value: String::from("tmp/filename with spaces.txt"),
|
||||
filename: Template {
|
||||
elements: vec![TemplateElement::String {
|
||||
value: String::from("tmp/filename with spaces.txt"),
|
||||
encoded: String::from("tmp/filename\\ with\\ spaces.txt"),
|
||||
}],
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 37)),
|
||||
},
|
||||
space1: Whitespace {
|
||||
|
@ -493,8 +493,12 @@ mod tests {
|
||||
value: String::new(),
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
|
||||
},
|
||||
filename: Filename {
|
||||
value: "hello.txt".to_string(),
|
||||
filename: Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello.txt".to_string(),
|
||||
encoded: "hello.txt".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 15)),
|
||||
},
|
||||
space1: Whitespace {
|
||||
@ -516,8 +520,12 @@ mod tests {
|
||||
value: String::new(),
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
|
||||
},
|
||||
filename: Filename {
|
||||
value: "hello.txt".to_string(),
|
||||
filename: Template {
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello.txt".to_string(),
|
||||
encoded: "hello.txt".to_string(),
|
||||
}],
|
||||
delimiter: None,
|
||||
source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 15)),
|
||||
},
|
||||
space1: Whitespace {
|
||||
|
@ -208,7 +208,7 @@ impl ToJson for File {
|
||||
("type".to_string(), JValue::String("file".to_string())),
|
||||
(
|
||||
"filename".to_string(),
|
||||
JValue::String(self.filename.value.clone()),
|
||||
JValue::String(self.filename.to_string()),
|
||||
),
|
||||
])
|
||||
}
|
||||
@ -250,7 +250,7 @@ impl ToJson for FileParam {
|
||||
("name".to_string(), JValue::String(self.key.to_string())),
|
||||
(
|
||||
"filename".to_string(),
|
||||
JValue::String(self.value.filename.value.clone()),
|
||||
JValue::String(self.value.filename.to_string()),
|
||||
),
|
||||
];
|
||||
if let Some(content_type) = self.value.content_type.clone() {
|
||||
@ -281,9 +281,9 @@ impl ToJson for EntryOption {
|
||||
let name = "value".to_string();
|
||||
let value = match &self.kind {
|
||||
OptionKind::AwsSigV4(value) => JValue::String(value.to_string()),
|
||||
OptionKind::CaCertificate(filename) => JValue::String(filename.value.clone()),
|
||||
OptionKind::ClientCert(filename) => JValue::String(filename.value.clone()),
|
||||
OptionKind::ClientKey(filename) => JValue::String(filename.value.clone()),
|
||||
OptionKind::CaCertificate(filename) => JValue::String(filename.to_string()),
|
||||
OptionKind::ClientCert(filename) => JValue::String(filename.to_string()),
|
||||
OptionKind::ClientKey(filename) => JValue::String(filename.to_string()),
|
||||
OptionKind::Compressed(value) => value.to_json(),
|
||||
OptionKind::ConnectTo(value) => JValue::String(value.to_string()),
|
||||
OptionKind::Delay(value) => value.to_json(),
|
||||
@ -296,7 +296,7 @@ impl ToJson for EntryOption {
|
||||
OptionKind::IpV4(value) => value.to_json(),
|
||||
OptionKind::IpV6(value) => value.to_json(),
|
||||
OptionKind::MaxRedirect(value) => value.to_json(),
|
||||
OptionKind::Output(filename) => JValue::String(filename.value.clone()),
|
||||
OptionKind::Output(filename) => JValue::String(filename.to_string()),
|
||||
OptionKind::PathAsIs(value) => value.to_json(),
|
||||
OptionKind::Proxy(value) => JValue::String(value.to_string()),
|
||||
OptionKind::Resolve(value) => JValue::String(value.to_string()),
|
||||
|
@ -774,13 +774,6 @@ impl Tokenizable for Comment {
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for Filename {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let s = self.value.replace(' ', "\\ ");
|
||||
vec![Token::String(s)]
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for JsonValue {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
|
@ -502,10 +502,7 @@ fn lint_hex(hex: &Hex) -> Hex {
|
||||
fn lint_file(file: &File) -> File {
|
||||
File {
|
||||
space0: empty_whitespace(),
|
||||
filename: Filename {
|
||||
value: file.filename.value.clone(),
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
},
|
||||
filename: lint_template(&file.filename),
|
||||
space1: empty_whitespace(),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user