Skip to content

Commit

Permalink
feat: excluded control chars in values
Browse files Browse the repository at this point in the history
  • Loading branch information
amunra committed Jan 29, 2024
1 parent 67a0dac commit ec563d3
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 4 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ service::key1=value1;key2=value2;key3=value3;
A few rules:
* The last semicolon is mandatory.
* Service name and keys are case-insensitive.
* Values are case-sensitive.
* Keys are ASCII alphanumeric and start with a letter.
* If a semicolon `;` appears in a value, escaped it as a double semicolon `;;`.
* Values are case-sensitive unicode strings which can contain any characters,
* Except control characters (`0x00..=0x1f` and `0x7f..=0x9f`).
* If semicolons `;` appears in a value, these are escaped as double semicolon `;;`.

## Grammar

Expand All @@ -33,7 +34,7 @@ alpha ::= "a".."z" | "A".."Z"
alphanumeric ::= "a".."z" | "A".."Z" | "0".."9"
value_char ::= non_semicolon_char | escaped_semicolon
escaped_semicolon ::= ";;"
non_semicolon_char ::= ? any character except ';' ?
non_semicolon_char ::= ? any unicode character except ';', 0x00..=0x1f and 0x7f..=0x9f ?
```

## Usage
Expand Down
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub enum ErrorKind {
ExpectedIdentifierNotEmpty,
BadSeparator((char, char)),
IncompleteKeyValue,
InvalidValueChar(char),
MissingTrailingSemicolon,
DuplicateKey(String),
}
Expand Down Expand Up @@ -128,6 +129,7 @@ impl Display for ErrorKind {
ErrorKind::IncompleteKeyValue => {
write!(f, "incomplete key-value pair before end of input")
}
ErrorKind::InvalidValueChar(c) => write!(f, "invalid value char {:?}", c),
ErrorKind::MissingTrailingSemicolon => write!(f, "missing trailing semicolon"),
ErrorKind::DuplicateKey(s) => write!(f, "duplicate key {:?}", s),
}
Expand Down Expand Up @@ -215,7 +217,10 @@ fn parse_value(
value.push(';');
}
(Some((_, ';')), _) => break,
(Some((_, c)), _) => {
(Some((p, c)), _) => {
if matches!(c, '\u{0}'..='\u{1f}' | '\u{7f}'..='\u{9f}') {
return Err(parse_err(ErrorKind::InvalidValueChar(c), p));
}
value.push(c);
let _ = iter.next();
}
Expand Down
19 changes: 19 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,22 @@ fn unicode_value() -> Result<(), ParsingError> {
assert_eq!(config.get("x"), Some("協定"));
Ok(())
}

#[test]
fn invalid_ctrl_chars_in_value() {
let bad_chars = [
'\x00', '\x01', '\x02', '\x03', '\x04', '\x1f', '\x7f', '\u{80}', '\u{8a}', '\u{9f}',
];
for bad in bad_chars {
let input = format!("http::x={};", bad);
let config = parse_conf_str(&input);
assert!(config.is_err());
let err = config.unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidValueChar(bad));
assert_eq!(err.position(), 8);
assert_eq!(
err.to_string(),
format!("invalid value char {:?} at position 8", bad)
);
}
}

0 comments on commit ec563d3

Please sign in to comment.