diff --git a/integration/tests/url.curl b/integration/tests/url.curl new file mode 100644 index 000000000..dffd5c17e --- /dev/null +++ b/integration/tests/url.curl @@ -0,0 +1,3 @@ +curl 'http://localhost:8000/~user' +curl 'http://localhost:8000/%7Euser' +curl 'http://localhost:8000/!$&()*+,;=:@[]' \ No newline at end of file diff --git a/integration/tests/url.html b/integration/tests/url.html index fb3cc11e6..cecca78e2 100644 --- a/integration/tests/url.html +++ b/integration/tests/url.html @@ -1,6 +1,14 @@
GET http://localhost:8000/~user
HTTP/1.0 200
+```user```
GET http://localhost:8000/%7Euser
HTTP/1.0 200
-
\ No newline at end of file
+```user```
+
+# TODO: add single quote (needs to be escaped in curl command-line)
+GET http://localhost:8000/!$&()*+,;=:@[]
+HTTP/1.0 200
+```weird```
+
+
\ No newline at end of file
diff --git a/integration/tests/url.hurl b/integration/tests/url.hurl
index 5b6918b79..3b0a3158a 100644
--- a/integration/tests/url.hurl
+++ b/integration/tests/url.hurl
@@ -1,5 +1,13 @@
GET http://localhost:8000/~user
HTTP/1.0 200
+```user```
GET http://localhost:8000/%7Euser
HTTP/1.0 200
+```user```
+
+# TODO: add single quote (needs to be escaped in curl command-line)
+GET http://localhost:8000/!$&()*+,;=:@[]
+HTTP/1.0 200
+```weird```
+
diff --git a/integration/tests/url.json b/integration/tests/url.json
index 47241e1d9..584b9373b 100644
--- a/integration/tests/url.json
+++ b/integration/tests/url.json
@@ -1 +1 @@
-{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/~user"},"response":{"version":"HTTP/1.0","status":200}},{"request":{"method":"GET","url":"http://localhost:8000/%7Euser"},"response":{"version":"HTTP/1.0","status":200}}]}
\ No newline at end of file
+{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/~user"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"user"}}},{"request":{"method":"GET","url":"http://localhost:8000/%7Euser"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"user"}}},{"request":{"method":"GET","url":"http://localhost:8000/!$&()*+,;=:@[]"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"weird"}}}]}
\ No newline at end of file
diff --git a/integration/tests/user.py b/integration/tests/user.py
index 132d6c918..3ef0db1ad 100644
--- a/integration/tests/user.py
+++ b/integration/tests/user.py
@@ -3,4 +3,8 @@ from tests import app
@app.route("/~user")
def url_with_tilde():
- return ''
\ No newline at end of file
+ return 'user'
+
+@app.route("/!$&()*+,;=:@[]")
+def url_weird():
+ return 'weird'
diff --git a/packages/hurl_core/src/parser/url.rs b/packages/hurl_core/src/parser/url.rs
index 833a0f506..48a5a2773 100644
--- a/packages/hurl_core/src/parser/url.rs
+++ b/packages/hurl_core/src/parser/url.rs
@@ -70,8 +70,9 @@ pub fn url(reader: &mut Reader) -> ParseResult<'static, Template> {
None => break,
Some(c) => {
if c.is_alphanumeric()
- || vec![
- ':', '/', '.', '-', '?', '=', '&', '_', '%', '*', ',', '@', '~',
+ | vec![
+ ':', '/', '.', '-', '?', '=', '&', '_', '%', '*', ',', '@',
+ '~', '+', '!', '$', '\'', '(', ')', ';', '[', ']',
]
.contains(&c)
{
@@ -251,4 +252,67 @@ mod tests {
assert_eq!(error.pos, Pos { line: 1, column: 1 });
assert_eq!(error.inner, ParseError::Url {});
}
+
+ #[test]
+ fn test_valid_urls() {
+ // from official url_test.go file
+ let valid_urls = [
+ "http://www.google.com",
+ "http://www.google.com/",
+ "http://www.google.com/file%20one%26two",
+ "http://www.google.com/#file%20one%26two",
+ "ftp://webmaster@www.google.com/",
+ "ftp://john%20doe@www.google.com/",
+ "http://www.google.com/?",
+ "http://www.google.com/?foo=bar?",
+ "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",
+ "http://user:password@google.com",
+ "http://user:password@google.com",
+ "http://j@ne:password@google.com",
+ "http://j%40ne:password@google.com",
+ "http://jane:p@ssword@google.com",
+ "http://j@ne:password@google.com/p@th?q=@go",
+ "http://j%40ne:password@google.com/p@th?q=@go",
+ "http://www.google.com/?q=go+language#foo",
+ "http://www.google.com/?q=go+language#foo&bar",
+ "http://www.google.com/?q=go+language#foo&bar",
+ "http://www.google.com/?q=go+language#foo%26bar",
+ "http://www.google.com/?q=go+language#foo%26bar",
+ "http://%3Fam:pa%3Fsword@google.com",
+ "http://192.168.0.1/",
+ "http://192.168.0.1:8080/",
+ "http://[fe80::1]/",
+ "http://[fe80::1]:8080/",
+ "http://[fe80::1%25en0]/",
+ "http://[fe80::1%25en0]:8080/",
+ "http://[fe80::1%25%65%6e%301-._~]/",
+ "http://[fe80::1%25en01-._~]/",
+ "http://[fe80::1%25%65%6e%301-._~]:8080/",
+ "http://rest.rsc.io/foo%2fbar/baz%2Fquux?alt=media",
+ "http://host/!$&'()*+,;=:@[hello]",
+ "http://example.com/oid/[order_id]",
+ "http://192.168.0.2:8080/foo",
+ "http://192.168.0.2:/foo",
+ "http://2b01:e34:ef40:7730:8e70:5aff:fefe:edac:8080/foo",
+ "http://2b01:e34:ef40:7730:8e70:5aff:fefe:edac:/foo",
+ "http://[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:8080/foo",
+ "http://[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:/foo",
+ "http://hello.世界.com/foo",
+ "http://hello.%E4%B8%96%E7%95%8C.com/foo",
+ "http://hello.%e4%b8%96%e7%95%8c.com/foo",
+ "http://hello.%E4%B8%96%E7%95%8C.com/foo",
+ "http://hello.%E4%B8%96%E7%95%8C.com/foo",
+ "http://example.com//foo",
+ ];
+ for s in valid_urls {
+ //eprintln!("{}", s);
+ let mut reader = Reader::init(s);
+ assert!(url(&mut reader).is_ok());
+ }
+ }
}