mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-09-11 05:35:53 +03:00
Update parser implem for filename with password
This commit is contained in:
parent
e1cdbc0ab2
commit
1b3943168b
@ -241,7 +241,7 @@ Short description:
|
|||||||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password">filename-password</span><span class="grammar-usedby">(used by <a href="#client-certificate-option">client-certificate-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-content">filename-password-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password">filename-password</span><span class="grammar-usedby">(used by <a href="#client-certificate-option">client-certificate-option</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-content">filename-password-content</a><span class="grammar-symbol">|</span><a href="#template">template</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||||||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-content">filename-password-content</span><span class="grammar-usedby">(used by <a href="#filename-password">filename-password</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-text">filename-password-text</a><span class="grammar-symbol">|</span><a href="#filename-password-escaped-char">filename-password-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-content">filename-password-content</span><span class="grammar-usedby">(used by <a href="#filename-password">filename-password</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-symbol">(</span><a href="#filename-password-text">filename-password-text</a><span class="grammar-symbol">|</span><a href="#filename-password-escaped-char">filename-password-escaped-char</a><span class="grammar-symbol">)</span><span class="grammar-symbol">*</span></div></div>
|
||||||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-text">filename-password-text</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#;{} \n\\]+</span></div></div>
|
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-text">filename-password-text</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-regex">~[#;{} \n\\]+</span></div></div>
|
||||||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-escaped-char">filename-password-escaped-char</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">;</span><span class="grammar-symbol">|</span><span class="grammar-literal"> </span><span class="grammar-symbol">|</span><span class="grammar-literal">{</span><span class="grammar-symbol">|</span><span class="grammar-literal">}</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="filename-password-escaped-char">filename-password-escaped-char</span><span class="grammar-usedby">(used by <a href="#filename-password-content">filename-password-content</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">\</span> <span class="grammar-symbol">(</span><span class="grammar-literal">\</span><span class="grammar-symbol">|</span><span class="grammar-literal">b</span><span class="grammar-symbol">|</span><span class="grammar-literal">f</span><span class="grammar-symbol">|</span><span class="grammar-literal">n</span><span class="grammar-symbol">|</span><span class="grammar-literal">r</span><span class="grammar-symbol">|</span><span class="grammar-literal">t</span><span class="grammar-symbol">|</span><span class="grammar-literal">#</span><span class="grammar-symbol">|</span><span class="grammar-literal">;</span><span class="grammar-symbol">|</span><span class="grammar-literal"> </span><span class="grammar-symbol">|</span><span class="grammar-literal">{</span><span class="grammar-symbol">|</span><span class="grammar-literal">}</span><span class="grammar-symbol">|</span><span class="grammar-literal">:</span><span class="grammar-symbol">|</span><span class="grammar-literal">u</span> <a href="#unicode-char">unicode-char</a><span class="grammar-symbol">)</span></div></div>
|
||||||
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="unicode-char">unicode-char</span><span class="grammar-usedby">(used by <a href="#quoted-string-escaped-char">quoted-string-escaped-char</a>, <a href="#key-string-escaped-char">key-string-escaped-char</a>, <a href="#value-string-escaped-char">value-string-escaped-char</a>, <a href="#oneline-string-escaped-char">oneline-string-escaped-char</a>, <a href="#multiline-string-escaped-char">multiline-string-escaped-char</a>, <a href="#filename-escaped-char">filename-escaped-char</a>, <a href="#filename-password-escaped-char">filename-password-escaped-char</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{</span> <a href="#hexdigit">hexdigit</a><span class="grammar-symbol">+</span> <span class="grammar-literal">}</span></div></div>
|
<div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="unicode-char">unicode-char</span><span class="grammar-usedby">(used by <a href="#quoted-string-escaped-char">quoted-string-escaped-char</a>, <a href="#key-string-escaped-char">key-string-escaped-char</a>, <a href="#value-string-escaped-char">value-string-escaped-char</a>, <a href="#oneline-string-escaped-char">oneline-string-escaped-char</a>, <a href="#multiline-string-escaped-char">multiline-string-escaped-char</a>, <a href="#filename-escaped-char">filename-escaped-char</a>, <a href="#filename-password-escaped-char">filename-password-escaped-char</a>)</span></div><div class="grammar-rule-expression"><span class="grammar-literal">{</span> <a href="#hexdigit">hexdigit</a><span class="grammar-symbol">+</span> <span class="grammar-literal">}</span></div></div>
|
||||||
</div><div class="grammar-ruleset"><h3 id="json">JSON</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-value">json-value</span><span class="grammar-usedby">(used by <a href="#bytes">bytes</a>, <a href="#json-key-value">json-key-value</a>, <a href="#json-array">json-array</a>)</span></div><div class="grammar-rule-expression"> <a href="#template">template</a><br>
|
</div><div class="grammar-ruleset"><h3 id="json">JSON</h3><div class="grammar-rule"><div class="grammar-rule-declaration"><span class="grammar-rule-id" id="json-value">json-value</span><span class="grammar-usedby">(used by <a href="#bytes">bytes</a>, <a href="#json-key-value">json-key-value</a>, <a href="#json-array">json-array</a>)</span></div><div class="grammar-rule-expression"> <a href="#template">template</a><br>
|
||||||
<span class="grammar-symbol">|</span><a href="#json-object">json-object</a><br>
|
<span class="grammar-symbol">|</span><a href="#json-object">json-object</a><br>
|
||||||
|
@ -443,7 +443,7 @@ filename-password-content: (filename-password-text | filename-password-escaped-c
|
|||||||
|
|
||||||
filename-password-text: ~[#;{} \n\\]+
|
filename-password-text: ~[#;{} \n\\]+
|
||||||
|
|
||||||
filename-password-escaped-char: "\\" ( "\\" | "b" | "f" | "n" | "r" | "t" | "#" | ";" | " " | "{" | "}" | "u" unicode-char)
|
filename-password-escaped-char: "\\" ( "\\" | "b" | "f" | "n" | "r" | "t" | "#" | ";" | " " | "{" | "}" | ":" | "u" unicode-char)
|
||||||
|
|
||||||
unicode-char: "{" hexdigit+ "}"
|
unicode-char: "{" hexdigit+ "}"
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">aws:amz:eu-central-1:sts</span></span>
|
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">aws:amz:eu-central-1:sts</span></span>
|
||||||
<span class="line"><span class="string">cacert</span>: <span class="filename">cacertfile</span></span>
|
<span class="line"><span class="string">cacert</span>: <span class="filename">cacertfile</span></span>
|
||||||
<span class="line"><span class="string">cert</span>: <span class="filename">certfile</span></span>
|
<span class="line"><span class="string">cert</span>: <span class="filename">certfile</span></span>
|
||||||
|
<span class="line"><span class="string">cert</span>: <span class="filename">certfile:qU114@q,["NO</span></span>
|
||||||
<span class="line"><span class="string">key</span>: <span class="filename">keyfile</span></span>
|
<span class="line"><span class="string">key</span>: <span class="filename">keyfile</span></span>
|
||||||
<span class="line"><span class="string">compressed</span>: <span class="boolean">false</span></span>
|
<span class="line"><span class="string">compressed</span>: <span class="boolean">false</span></span>
|
||||||
<span class="line"><span class="string">connect-to</span>: <span class="string">example.com:443:example.net:8443</span></span>
|
<span class="line"><span class="string">connect-to</span>: <span class="string">example.com:443:example.net:8443</span></span>
|
||||||
@ -42,7 +43,7 @@
|
|||||||
<span class="line"><span class="section-header">[Options]</span></span>
|
<span class="line"><span class="section-header">[Options]</span></span>
|
||||||
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">{{aws-sigv4}}</span></span>
|
<span class="line"><span class="string">aws-sigv4</span>: <span class="string">{{aws-sigv4}}</span></span>
|
||||||
<span class="line"></span><span class="comment">#cacert: {{cacert}} NOT SUPPORTED YET</span>
|
<span class="line"></span><span class="comment">#cacert: {{cacert}} NOT SUPPORTED YET</span>
|
||||||
<span class="line"></span><span class="comment">#cert: {{cert}} NOT SUPPORTED YET</span>
|
<span class="line"><span class="string">cert</span>: <span class="filename">{{cert}}</span></span>
|
||||||
<span class="line"></span><span class="comment">#key: {{key}} NOT SUPPORTED YET</span>
|
<span class="line"></span><span class="comment">#key: {{key}} NOT SUPPORTED YET</span>
|
||||||
<span class="line"><span class="string">compressed</span>: <span class="expr">{{compressed}}</span></span>
|
<span class="line"><span class="string">compressed</span>: <span class="expr">{{compressed}}</span></span>
|
||||||
<span class="line"><span class="string">connect-to</span>: <span class="string">{{connect-to}}</span></span>
|
<span class="line"><span class="string">connect-to</span>: <span class="string">{{connect-to}}</span></span>
|
||||||
|
@ -3,6 +3,7 @@ GET http://localhost:8000/hello
|
|||||||
aws-sigv4: aws:amz:eu-central-1:sts
|
aws-sigv4: aws:amz:eu-central-1:sts
|
||||||
cacert: cacertfile
|
cacert: cacertfile
|
||||||
cert: certfile
|
cert: certfile
|
||||||
|
cert: certfile:qU114@q,["NO
|
||||||
key: keyfile
|
key: keyfile
|
||||||
compressed: false
|
compressed: false
|
||||||
connect-to: example.com:443:example.net:8443
|
connect-to: example.com:443:example.net:8443
|
||||||
@ -42,7 +43,7 @@ GET http://localhost:8000/hello
|
|||||||
[Options]
|
[Options]
|
||||||
aws-sigv4: {{aws-sigv4}}
|
aws-sigv4: {{aws-sigv4}}
|
||||||
#cacert: {{cacert}} NOT SUPPORTED YET
|
#cacert: {{cacert}} NOT SUPPORTED YET
|
||||||
#cert: {{cert}} NOT SUPPORTED YET
|
cert: {{cert}}
|
||||||
#key: {{key}} NOT SUPPORTED YET
|
#key: {{key}} NOT SUPPORTED YET
|
||||||
compressed: {{compressed}}
|
compressed: {{compressed}}
|
||||||
connect-to: {{connect-to}}
|
connect-to: {{connect-to}}
|
||||||
|
@ -1 +1 @@
|
|||||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello","options":[{"name":"aws-sigv4","value":"aws:amz:eu-central-1:sts"},{"name":"cacert","value":"cacertfile"},{"name":"cert","value":"certfile"},{"name":"key","value":"keyfile"},{"name":"compressed","value":false},{"name":"connect-to","value":"example.com:443:example.net:8443"},{"name":"delay","value":1000},{"name":"location","value":false},{"name":"location-trusted","value":false},{"name":"http1.0","value":false},{"name":"http1.1","value":false},{"name":"http2","value":false},{"name":"http3","value":false},{"name":"insecure","value":false},{"name":"ipv4","value":false},{"name":"ipv6","value":false},{"name":"max-redirs","value":10},{"name":"netrc","value":false},{"name":"netrc-file","value":"netrcfile"},{"name":"netrc-optional","value":false},{"name":"output","value":"output.txt"},{"name":"path-as-is","value":false},{"name":"proxy","value":"http://proxy.example"},{"name":"resolve","value":"example.com:443:127.0.0.1"},{"name":"retry","value":0},{"name":"retry","value":-1},{"name":"retry","value":4},{"name":"retry-interval","value":1000},{"name":"skip","value":false},{"name":"unix-socket","value":"build/unix_socket.sock"},{"name":"variable","value":"user=null"},{"name":"variable","value":"status=true"},{"name":"variable","value":"count=2"},{"name":"variable","value":"score=7.7"},{"name":"variable","value":"name=Bob"},{"name":"verbose","value":false},{"name":"very-verbose","value":false}]}},{"request":{"method":"GET","url":"http://localhost:8000/hello","options":[{"name":"aws-sigv4","value":"{{aws-sigv4}}"},{"name":"compressed","value":"{{compressed}}"},{"name":"connect-to","value":"{{connect-to}}"},{"name":"delay","value":"{{delay}}"},{"name":"location","value":"{{location}}"},{"name":"http1.0","value":"{{http10}}"},{"name":"http1.1","value":"{{http11}}"},{"name":"http2","value":"{{http2}}"},{"name":"http3","value":"{{http3}}"},{"name":"insecure","value":"{{insecure}}"},{"name":"ipv4","value":"{{ipv4}}"},{"name":"ipv6","value":"{{ipv6}}"},{"name":"max-redirs","value":"{{max-redirs}}"},{"name":"netrc","value":"{{netrc}}"},{"name":"netrc-optional","value":"{{netrc-optional}}"},{"name":"path-as-is","value":"{{path-as-is}}"},{"name":"proxy","value":"{{proxy}}"},{"name":"resolve","value":"{{resolve}}"},{"name":"retry","value":"{{retry}}"},{"name":"retry-interval","value":"{{retry-interval}}"},{"name":"skip","value":"{{skip}}"},{"name":"unix-socket","value":"{{socket_file}}"},{"name":"verbose","value":"{{verbose}}"},{"name":"very-verbose","value":"{{very-verbose}}"}]}}]}
|
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello","options":[{"name":"aws-sigv4","value":"aws:amz:eu-central-1:sts"},{"name":"cacert","value":"cacertfile"},{"name":"cert","value":"certfile"},{"name":"cert","value":"certfile:qU114@q,[\"NO"},{"name":"key","value":"keyfile"},{"name":"compressed","value":false},{"name":"connect-to","value":"example.com:443:example.net:8443"},{"name":"delay","value":1000},{"name":"location","value":false},{"name":"location-trusted","value":false},{"name":"http1.0","value":false},{"name":"http1.1","value":false},{"name":"http2","value":false},{"name":"http3","value":false},{"name":"insecure","value":false},{"name":"ipv4","value":false},{"name":"ipv6","value":false},{"name":"max-redirs","value":10},{"name":"netrc","value":false},{"name":"netrc-file","value":"netrcfile"},{"name":"netrc-optional","value":false},{"name":"output","value":"output.txt"},{"name":"path-as-is","value":false},{"name":"proxy","value":"http://proxy.example"},{"name":"resolve","value":"example.com:443:127.0.0.1"},{"name":"retry","value":0},{"name":"retry","value":-1},{"name":"retry","value":4},{"name":"retry-interval","value":1000},{"name":"skip","value":false},{"name":"unix-socket","value":"build/unix_socket.sock"},{"name":"variable","value":"user=null"},{"name":"variable","value":"status=true"},{"name":"variable","value":"count=2"},{"name":"variable","value":"score=7.7"},{"name":"variable","value":"name=Bob"},{"name":"verbose","value":false},{"name":"very-verbose","value":false}]}},{"request":{"method":"GET","url":"http://localhost:8000/hello","options":[{"name":"aws-sigv4","value":"{{aws-sigv4}}"},{"name":"cert","value":"{{cert}}"},{"name":"compressed","value":"{{compressed}}"},{"name":"connect-to","value":"{{connect-to}}"},{"name":"delay","value":"{{delay}}"},{"name":"location","value":"{{location}}"},{"name":"http1.0","value":"{{http10}}"},{"name":"http1.1","value":"{{http11}}"},{"name":"http2","value":"{{http2}}"},{"name":"http3","value":"{{http3}}"},{"name":"insecure","value":"{{insecure}}"},{"name":"ipv4","value":"{{ipv4}}"},{"name":"ipv6","value":"{{ipv6}}"},{"name":"max-redirs","value":"{{max-redirs}}"},{"name":"netrc","value":"{{netrc}}"},{"name":"netrc-optional","value":"{{netrc-optional}}"},{"name":"path-as-is","value":"{{path-as-is}}"},{"name":"proxy","value":"{{proxy}}"},{"name":"resolve","value":"{{resolve}}"},{"name":"retry","value":"{{retry}}"},{"name":"retry-interval","value":"{{retry-interval}}"},{"name":"skip","value":"{{skip}}"},{"name":"unix-socket","value":"{{socket_file}}"},{"name":"verbose","value":"{{verbose}}"},{"name":"very-verbose","value":"{{very-verbose}}"}]}}]}
|
||||||
|
@ -3,6 +3,7 @@ GET http://localhost:8000/hello
|
|||||||
aws-sigv4: aws:amz:eu-central-1:sts
|
aws-sigv4: aws:amz:eu-central-1:sts
|
||||||
cacert: cacertfile
|
cacert: cacertfile
|
||||||
cert: certfile
|
cert: certfile
|
||||||
|
cert: certfile:qU114@q,["NO
|
||||||
key: keyfile
|
key: keyfile
|
||||||
compressed: false
|
compressed: false
|
||||||
connect-to: example.com:443:example.net:8443
|
connect-to: example.com:443:example.net:8443
|
||||||
@ -42,7 +43,7 @@ GET http://localhost:8000/hello
|
|||||||
[Options]
|
[Options]
|
||||||
aws-sigv4: {{aws-sigv4}}
|
aws-sigv4: {{aws-sigv4}}
|
||||||
#cacert: {{cacert}} NOT SUPPORTED YET
|
#cacert: {{cacert}} NOT SUPPORTED YET
|
||||||
#cert: {{cert}} NOT SUPPORTED YET
|
cert: {{cert}}
|
||||||
#key: {{key}} NOT SUPPORTED YET
|
#key: {{key}} NOT SUPPORTED YET
|
||||||
compressed: {{compressed}}
|
compressed: {{compressed}}
|
||||||
connect-to: {{connect-to}}
|
connect-to: {{connect-to}}
|
||||||
|
@ -22,6 +22,12 @@ use crate::parser::reader::Reader;
|
|||||||
use crate::parser::template::template;
|
use crate::parser::template::template;
|
||||||
use crate::parser::{string, ParseResult};
|
use crate::parser::{string, ParseResult};
|
||||||
|
|
||||||
|
/// Parse a filename.
|
||||||
|
///
|
||||||
|
/// A few characters need to be escaped such as space
|
||||||
|
/// for example: file\ with\ space.txt
|
||||||
|
/// This is very similar to the behaviour in a standard shell.
|
||||||
|
///
|
||||||
pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
||||||
let start = reader.state;
|
let start = reader.state;
|
||||||
|
|
||||||
@ -105,26 +111,15 @@ fn filename_text(reader: &mut Reader) -> String {
|
|||||||
match reader.read() {
|
match reader.read() {
|
||||||
None => break,
|
None => break,
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
if c.is_alphanumeric()
|
if ['#', ';', '{', '}', ' ', '\n', '\\'].contains(&c) {
|
||||||
|| c == '_'
|
|
||||||
|| c == '-'
|
|
||||||
|| c == '.'
|
|
||||||
|| c == '['
|
|
||||||
|| c == ']'
|
|
||||||
|| c == '@'
|
|
||||||
|| c == '$'
|
|
||||||
|| c == '/'
|
|
||||||
|| c == ':'
|
|
||||||
{
|
|
||||||
s.push(c);
|
|
||||||
} else {
|
|
||||||
reader.state = save;
|
reader.state = save;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
s.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,19 +127,17 @@ fn filename_escaped_char(reader: &mut Reader) -> ParseResult<char> {
|
|||||||
try_literal("\\", reader)?;
|
try_literal("\\", reader)?;
|
||||||
let start = reader.state;
|
let start = reader.state;
|
||||||
match reader.read() {
|
match reader.read() {
|
||||||
Some(';') => Ok(';'),
|
|
||||||
Some('#') => Ok('#'),
|
|
||||||
Some('[') => Ok('['),
|
|
||||||
Some(' ') => Ok(' '),
|
|
||||||
Some(']') => Ok(']'),
|
|
||||||
Some(':') => Ok(':'),
|
|
||||||
Some('\\') => Ok('\\'),
|
Some('\\') => Ok('\\'),
|
||||||
Some('/') => Ok('/'),
|
|
||||||
Some('b') => Ok('\x08'),
|
Some('b') => Ok('\x08'),
|
||||||
Some('f') => Ok('\x0c'),
|
Some('f') => Ok('\x0c'),
|
||||||
Some('n') => Ok('\n'),
|
Some('n') => Ok('\n'),
|
||||||
Some('r') => Ok('\r'),
|
Some('r') => Ok('\r'),
|
||||||
Some('t') => Ok('\t'),
|
Some('t') => Ok('\t'),
|
||||||
|
Some('#') => Ok('#'),
|
||||||
|
Some(';') => Ok(';'),
|
||||||
|
Some(' ') => Ok(' '),
|
||||||
|
Some('{') => Ok('{'),
|
||||||
|
Some('}') => Ok('}'),
|
||||||
Some('u') => string::unicode(reader),
|
Some('u') => string::unicode(reader),
|
||||||
_ => Err(Error::new(start.pos, false, ParseError::EscapeChar)),
|
_ => Err(Error::new(start.pos, false, ParseError::EscapeChar)),
|
||||||
}
|
}
|
||||||
@ -204,12 +197,34 @@ mod tests {
|
|||||||
assert_eq!(reader.state.cursor, 18);
|
assert_eq!(reader.state.cursor, 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_escaped_chars() {
|
||||||
|
let mut reader = Reader::new("filename\\{"); // to the possible escaped chars
|
||||||
|
assert_eq!(
|
||||||
|
parse(&mut reader).unwrap(),
|
||||||
|
Template {
|
||||||
|
delimiter: None,
|
||||||
|
elements: vec![TemplateElement::String {
|
||||||
|
value: "filename{".to_string(),
|
||||||
|
encoded: "filename\\{".to_string()
|
||||||
|
}],
|
||||||
|
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 11)),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(reader.state.cursor, 10);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_filename_error() {
|
fn test_filename_error() {
|
||||||
let mut reader = Reader::new("???");
|
let mut reader = Reader::new("{");
|
||||||
let error = parse(&mut reader).err().unwrap();
|
let error = parse(&mut reader).err().unwrap();
|
||||||
assert_eq!(error.inner, ParseError::Filename);
|
assert_eq!(error.inner, ParseError::Filename);
|
||||||
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
||||||
|
|
||||||
|
let mut reader = Reader::new("\\:");
|
||||||
|
let error = parse(&mut reader).err().unwrap();
|
||||||
|
assert_eq!(error.inner, ParseError::EscapeChar);
|
||||||
|
assert_eq!(error.pos, Pos { line: 1, column: 2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -226,7 +241,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
TemplateElement::Expression(Expr {
|
TemplateElement::Expression(Expr {
|
||||||
space0: Whitespace {
|
space0: Whitespace {
|
||||||
value: "".to_string(),
|
value: String::new(),
|
||||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 7)),
|
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 7)),
|
||||||
},
|
},
|
||||||
variable: Variable {
|
variable: Variable {
|
||||||
@ -234,7 +249,7 @@ mod tests {
|
|||||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 10)),
|
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 10)),
|
||||||
},
|
},
|
||||||
space1: Whitespace {
|
space1: Whitespace {
|
||||||
value: "".to_string(),
|
value: String::new(),
|
||||||
source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 10)),
|
source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 10)),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -255,7 +270,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
TemplateElement::Expression(Expr {
|
TemplateElement::Expression(Expr {
|
||||||
space0: Whitespace {
|
space0: Whitespace {
|
||||||
value: "".to_string(),
|
value: String::new(),
|
||||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 7)),
|
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 7)),
|
||||||
},
|
},
|
||||||
variable: Variable {
|
variable: Variable {
|
||||||
@ -263,7 +278,7 @@ mod tests {
|
|||||||
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 10)),
|
source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 10)),
|
||||||
},
|
},
|
||||||
space1: Whitespace {
|
space1: Whitespace {
|
||||||
value: "".to_string(),
|
value: String::new(),
|
||||||
source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 10)),
|
source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 10)),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
174
packages/hurl_core/src/parser/filename_password.rs
Normal file
174
packages/hurl_core/src/parser/filename_password.rs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Hurl (https://hurl.dev)
|
||||||
|
* Copyright (C) 2024 Orange
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
use crate::ast::*;
|
||||||
|
use crate::parser::error::*;
|
||||||
|
use crate::parser::primitives::try_literal;
|
||||||
|
use crate::parser::reader::Reader;
|
||||||
|
use crate::parser::template::template;
|
||||||
|
use crate::parser::{string, ParseResult};
|
||||||
|
|
||||||
|
/// Parse a filename with an optional password
|
||||||
|
///
|
||||||
|
/// This is very similar to the filename parser.
|
||||||
|
/// There is still a small different due to the password delimiter ":"
|
||||||
|
/// If the ':' character is part of the filename, it must be escaped.
|
||||||
|
/// While in the standard filename parser, you can not escape this character at all.
|
||||||
|
///
|
||||||
|
pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
||||||
|
let start = reader.state;
|
||||||
|
|
||||||
|
let mut elements = vec![];
|
||||||
|
loop {
|
||||||
|
let start = reader.state;
|
||||||
|
match template(reader) {
|
||||||
|
Ok(expr) => {
|
||||||
|
let element = TemplateElement::Expression(expr);
|
||||||
|
elements.push(element);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if e.recoverable {
|
||||||
|
let value = filename_password_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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = reader.state;
|
||||||
|
Ok(Template {
|
||||||
|
delimiter: None,
|
||||||
|
elements,
|
||||||
|
source_info: SourceInfo {
|
||||||
|
start: start.pos,
|
||||||
|
end: end.pos,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filename_password_content(reader: &mut Reader) -> ParseResult<String> {
|
||||||
|
let mut s = String::new();
|
||||||
|
loop {
|
||||||
|
match filename_password_escaped_char(reader) {
|
||||||
|
Ok(c) => {
|
||||||
|
// ':' is escaped so that is it not recognized as the password delimiter
|
||||||
|
// This is not due to Hurl format
|
||||||
|
if c == ':' {
|
||||||
|
s.push('\\');
|
||||||
|
}
|
||||||
|
s.push(c);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if e.recoverable {
|
||||||
|
let s2 = filename_password_text(reader);
|
||||||
|
if s2.is_empty() {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
s.push_str(&s2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filename_password_text(reader: &mut Reader) -> String {
|
||||||
|
let mut s = String::new();
|
||||||
|
loop {
|
||||||
|
let save = reader.state;
|
||||||
|
match reader.read() {
|
||||||
|
None => break,
|
||||||
|
Some(c) => {
|
||||||
|
if ['#', ';', '{', '}', '\n', '\\'].contains(&c) {
|
||||||
|
reader.state = save;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
s.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filename_password_escaped_char(reader: &mut Reader) -> ParseResult<char> {
|
||||||
|
try_literal("\\", reader)?;
|
||||||
|
let start = reader.state;
|
||||||
|
match reader.read() {
|
||||||
|
Some('\\') => Ok('\\'),
|
||||||
|
Some('b') => Ok('\x08'),
|
||||||
|
Some('f') => Ok('\x0c'),
|
||||||
|
Some('n') => Ok('\n'),
|
||||||
|
Some('r') => Ok('\r'),
|
||||||
|
Some('t') => Ok('\t'),
|
||||||
|
Some('#') => Ok('#'),
|
||||||
|
Some(';') => Ok(';'),
|
||||||
|
Some(' ') => Ok(' '),
|
||||||
|
Some('{') => Ok('{'),
|
||||||
|
Some('}') => Ok('}'),
|
||||||
|
Some(':') => Ok(':'),
|
||||||
|
Some('u') => string::unicode(reader),
|
||||||
|
_ => Err(Error::new(start.pos, false, ParseError::EscapeChar)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::ast::Pos;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_filename_with_password() {
|
||||||
|
let mut reader = Reader::new("file\\:123:pwd\\:\\#:");
|
||||||
|
assert_eq!(
|
||||||
|
parse(&mut reader).unwrap(),
|
||||||
|
Template {
|
||||||
|
delimiter: None,
|
||||||
|
elements: vec![TemplateElement::String {
|
||||||
|
value: "file\\:123:pwd\\:#:".to_string(),
|
||||||
|
encoded: "file\\:123:pwd\\:\\#:".to_string()
|
||||||
|
}],
|
||||||
|
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 19)),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(reader.state.cursor, 18);
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ mod cookiepath;
|
|||||||
mod error;
|
mod error;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod filename;
|
mod filename;
|
||||||
|
mod filename_password;
|
||||||
mod filter;
|
mod filter;
|
||||||
mod json;
|
mod json;
|
||||||
mod key_string;
|
mod key_string;
|
||||||
|
@ -23,7 +23,7 @@ use crate::parser::number::{integer, natural, number};
|
|||||||
use crate::parser::primitives::*;
|
use crate::parser::primitives::*;
|
||||||
use crate::parser::reader::Reader;
|
use crate::parser::reader::Reader;
|
||||||
use crate::parser::string::*;
|
use crate::parser::string::*;
|
||||||
use crate::parser::{expr, filename, ParseResult};
|
use crate::parser::{expr, filename, filename_password, ParseResult};
|
||||||
|
|
||||||
/// Parse an option in an `[Options]` section.
|
/// Parse an option in an `[Options]` section.
|
||||||
pub fn parse(reader: &mut Reader) -> ParseResult<EntryOption> {
|
pub fn parse(reader: &mut Reader) -> ParseResult<EntryOption> {
|
||||||
@ -101,7 +101,7 @@ fn option_cacert(reader: &mut Reader) -> ParseResult<OptionKind> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn option_cert(reader: &mut Reader) -> ParseResult<OptionKind> {
|
fn option_cert(reader: &mut Reader) -> ParseResult<OptionKind> {
|
||||||
let value = filename::parse(reader)?;
|
let value = filename_password::parse(reader)?;
|
||||||
Ok(OptionKind::ClientCert(value))
|
Ok(OptionKind::ClientCert(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user