Make URLs strictier: must begins with http://, https:// or {{.

This commit is contained in:
jcamiel 2023-07-04 18:19:08 +02:00 committed by hurl-bot
parent b7aa675f6a
commit 264c6f290b
No known key found for this signature in database
GPG Key ID: 1283A2B4A0DCAF8D
15 changed files with 79 additions and 14 deletions

View File

@ -0,0 +1,7 @@
error: Parsing URL
--> tests_error_parser/invalid_url_1.hurl:1:5
|
1 | GET localhost:8000
| ^ expecting http://, https:// or {{
|

View File

@ -0,0 +1 @@
2

View File

@ -0,0 +1 @@
GET localhost:8000

View File

@ -0,0 +1,3 @@
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
hurl tests_error_parser/invalid_url_1.hurl

View File

@ -0,0 +1,3 @@
#!/bin/bash
set -Eeuo pipefail
hurl tests_error_parser/invalid_url_1.hurl

View File

@ -0,0 +1,7 @@
error: Parsing URL
--> tests_error_parser/invalid_url_2.hurl:1:5
|
1 | GET http:localhost:8000
| ^ expecting http://, https:// or {{
|

View File

@ -0,0 +1 @@
2

View File

@ -0,0 +1 @@
GET http:localhost:8000

View File

@ -0,0 +1,3 @@
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
hurl tests_error_parser/invalid_url_2.hurl

View File

@ -0,0 +1,3 @@
#!/bin/bash
set -Eeuo pipefail
hurl tests_error_parser/invalid_url_2.hurl

View File

@ -1,7 +1,7 @@
error: Parsing URL
--> tests_error_parser/url_bad_prefix.hurl:2:5
--> tests_error_parser/url_bad_prefix.hurl:4:5
|
2 | GET "http://localhost:8000"
| ^ illegal character <">
4 | GET "http://localhost:8000"
| ^ expecting http://, https:// or {{
|

View File

@ -1,2 +1,4 @@
# Url are are `value-string` in Hurl format.
# URL in Hurl are not quoted strings:
# it's should be:
# GET http://localhost:8000
GET "http://localhost:8000"

View File

@ -59,6 +59,7 @@ impl Error for parser::Error {
ParseError::InvalidCookieAttribute { .. } => "Parsing cookie attribute".to_string(),
ParseError::OddNumberOfHexDigits { .. } => "Parsing hex bytearray".to_string(),
ParseError::UrlIllegalCharacter(_) => "Parsing URL".to_string(),
ParseError::UrlInvalidStart => "Parsing URL".to_string(),
ParseError::Multiline => "Parsing multiline".to_string(),
ParseError::GraphQlVariables => "Parsing GraphQL variables".to_string(),
_ => format!("{self:?}"),
@ -112,6 +113,7 @@ impl Error for parser::Error {
"expecting an even number of hex digits".to_string()
}
ParseError::UrlIllegalCharacter(c) => format!("illegal character <{c}>"),
ParseError::UrlInvalidStart => "expecting http://, https:// or {{".to_string(),
ParseError::Multiline => "the multiline is not valid".to_string(),
ParseError::GraphQlVariables => "GraphQL variables is not a valid JSON object".to_string(),
_ => format!("{self:?}"),

View File

@ -60,6 +60,7 @@ pub enum ParseError {
InvalidCookieAttribute,
OddNumberOfHexDigits,
UrlIllegalCharacter(char),
UrlInvalidStart,
InvalidOption,
Multiline,
GraphQlVariables,

View File

@ -22,7 +22,7 @@ use crate::parser::reader::Reader;
use crate::parser::{expr, ParseResult};
pub fn url(reader: &mut Reader) -> ParseResult<'static, Template> {
// Can not be json-encoded, nor empty.
// Can not be JSON-encoded, nor empty.
// But more restrictive: whitelist characters, not empty
let start = reader.state.clone();
@ -37,13 +37,11 @@ pub fn url(reader: &mut Reader) -> ParseResult<'static, Template> {
});
}
// Urls must begin with http/https or { (templates).
let first_char = reader.peek();
if first_char != Some('h') && first_char != Some('{') {
if !url_prefix_valid(reader) {
return Err(Error {
pos: reader.state.pos.clone(),
recoverable: false,
inner: ParseError::UrlIllegalCharacter(first_char.unwrap()),
inner: ParseError::UrlInvalidStart,
});
}
@ -110,7 +108,7 @@ pub fn url(reader: &mut Reader) -> ParseResult<'static, Template> {
});
}
// url should be followed by a line terminator
// URLs should be followed by a line terminator
let save = reader.state.clone();
if line_terminator(reader).is_err() {
reader.state = save;
@ -133,6 +131,18 @@ pub fn url(reader: &mut Reader) -> ParseResult<'static, Template> {
})
}
/// Returns true if url starts with http://, https:// or {{
fn url_prefix_valid(reader: &mut Reader) -> bool {
let prefixes = ["https://", "http://", "{{"];
for expected_p in prefixes.iter() {
let current_p = reader.peek_n(expected_p.len());
if &current_p == expected_p {
return true;
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
@ -256,7 +266,7 @@ mod tests {
let mut reader = Reader::new(" # eol");
let error = url(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 1 });
assert_eq!(error.inner, ParseError::UrlIllegalCharacter(' '));
assert_eq!(error.inner, ParseError::UrlInvalidStart);
}
#[test]
@ -272,9 +282,11 @@ mod tests {
"http://www.google.com/?q=go+language",
"http://www.google.com/?q=go%20language",
"http://www.google.com/a%20b?q=c+d",
"http:www.google.com/?q=go+language",
"http:www.google.com/?q=go+language",
"http:%2f%2fwww.google.com/?q=go+language",
// The following URLs are supported in the Go test file
// but are not considered as valid URLs by curl
// "http:www.google.com/?q=go+language",
// "http:www.google.com/?q=go+language",
// "http:%2f%2fwww.google.com/?q=go+language",
"http://user:password@google.com",
"http://user:password@google.com",
"http://j@ne:password@google.com",
@ -319,4 +331,22 @@ mod tests {
assert!(url(&mut reader).is_ok());
}
}
#[test]
fn test_invalid_urls() {
// from official url_test.go file
let invalid_urls = [
"foo.com",
"httpfoo.com",
"http:foo.com",
"https:foo.com",
"https:/foo.com",
"{https://foo.com",
];
for s in invalid_urls {
let mut reader = Reader::new(s);
assert!(url(&mut reader).is_err());
}
}
}