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()); + } + } }