diff --git a/integration/tests_error_parser/invalid_url_1.err b/integration/tests_error_parser/invalid_url_1.err new file mode 100644 index 000000000..99d6fdf35 --- /dev/null +++ b/integration/tests_error_parser/invalid_url_1.err @@ -0,0 +1,7 @@ +error: Parsing URL + --> tests_error_parser/invalid_url_1.hurl:1:5 + | + 1 | GET localhost:8000 + | ^ expecting http://, https:// or {{ + | + diff --git a/integration/tests_error_parser/invalid_url_1.exit b/integration/tests_error_parser/invalid_url_1.exit new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/integration/tests_error_parser/invalid_url_1.exit @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/integration/tests_error_parser/invalid_url_1.hurl b/integration/tests_error_parser/invalid_url_1.hurl new file mode 100644 index 000000000..2626e08ee --- /dev/null +++ b/integration/tests_error_parser/invalid_url_1.hurl @@ -0,0 +1 @@ +GET localhost:8000 diff --git a/integration/tests_error_parser/invalid_url_1.ps1 b/integration/tests_error_parser/invalid_url_1.ps1 new file mode 100644 index 000000000..68c73ccbe --- /dev/null +++ b/integration/tests_error_parser/invalid_url_1.ps1 @@ -0,0 +1,3 @@ +Set-StrictMode -Version latest +$ErrorActionPreference = 'Stop' +hurl tests_error_parser/invalid_url_1.hurl diff --git a/integration/tests_error_parser/invalid_url_1.sh b/integration/tests_error_parser/invalid_url_1.sh new file mode 100755 index 000000000..9165bf4ac --- /dev/null +++ b/integration/tests_error_parser/invalid_url_1.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -Eeuo pipefail +hurl tests_error_parser/invalid_url_1.hurl diff --git a/integration/tests_error_parser/invalid_url_2.err b/integration/tests_error_parser/invalid_url_2.err new file mode 100644 index 000000000..bfae406bd --- /dev/null +++ b/integration/tests_error_parser/invalid_url_2.err @@ -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 {{ + | + diff --git a/integration/tests_error_parser/invalid_url_2.exit b/integration/tests_error_parser/invalid_url_2.exit new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/integration/tests_error_parser/invalid_url_2.exit @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/integration/tests_error_parser/invalid_url_2.hurl b/integration/tests_error_parser/invalid_url_2.hurl new file mode 100644 index 000000000..0fa8679f2 --- /dev/null +++ b/integration/tests_error_parser/invalid_url_2.hurl @@ -0,0 +1 @@ +GET http:localhost:8000 diff --git a/integration/tests_error_parser/invalid_url_2.ps1 b/integration/tests_error_parser/invalid_url_2.ps1 new file mode 100644 index 000000000..c0a0f25ca --- /dev/null +++ b/integration/tests_error_parser/invalid_url_2.ps1 @@ -0,0 +1,3 @@ +Set-StrictMode -Version latest +$ErrorActionPreference = 'Stop' +hurl tests_error_parser/invalid_url_2.hurl diff --git a/integration/tests_error_parser/invalid_url_2.sh b/integration/tests_error_parser/invalid_url_2.sh new file mode 100755 index 000000000..957c302a7 --- /dev/null +++ b/integration/tests_error_parser/invalid_url_2.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -Eeuo pipefail +hurl tests_error_parser/invalid_url_2.hurl diff --git a/integration/tests_error_parser/url_bad_prefix.err b/integration/tests_error_parser/url_bad_prefix.err index 323504f5f..a05d3ccad 100644 --- a/integration/tests_error_parser/url_bad_prefix.err +++ b/integration/tests_error_parser/url_bad_prefix.err @@ -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 {{ | diff --git a/integration/tests_error_parser/url_bad_prefix.hurl b/integration/tests_error_parser/url_bad_prefix.hurl index fb139b13f..fd27717fe 100644 --- a/integration/tests_error_parser/url_bad_prefix.hurl +++ b/integration/tests_error_parser/url_bad_prefix.hurl @@ -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" \ No newline at end of file diff --git a/packages/hurl_core/src/error/mod.rs b/packages/hurl_core/src/error/mod.rs index b8d8a1c99..641148f7b 100644 --- a/packages/hurl_core/src/error/mod.rs +++ b/packages/hurl_core/src/error/mod.rs @@ -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:?}"), diff --git a/packages/hurl_core/src/parser/error.rs b/packages/hurl_core/src/parser/error.rs index 5089bbaef..be1c5351f 100644 --- a/packages/hurl_core/src/parser/error.rs +++ b/packages/hurl_core/src/parser/error.rs @@ -60,6 +60,7 @@ pub enum ParseError { InvalidCookieAttribute, OddNumberOfHexDigits, UrlIllegalCharacter(char), + UrlInvalidStart, InvalidOption, Multiline, GraphQlVariables, diff --git a/packages/hurl_core/src/parser/url.rs b/packages/hurl_core/src/parser/url.rs index 34a71dd03..75d6bb7fd 100644 --- a/packages/hurl_core/src/parser/url.rs +++ b/packages/hurl_core/src/parser/url.rs @@ -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 ¤t_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()); + } + } }