mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-26 00:22:10 +03:00
Remove public visibility of mod http.
This commit is contained in:
parent
ae4acfbec1
commit
2d1cbcc694
@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use crate::cli::CliError;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
|
@ -15,7 +15,14 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use crate::cli;
|
||||
use crate::cli::CliError;
|
||||
use crate::runner::RunnerOptionsBuilder;
|
||||
use crate::runner::{RunnerOptions, Value, Verbosity};
|
||||
use atty::Stream;
|
||||
use clap::{value_parser, ArgAction, ArgMatches, Command};
|
||||
use hurl::util::path::ContextDir;
|
||||
use hurl_core::ast::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
@ -23,16 +30,6 @@ use std::io::{BufRead, BufReader};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{value_parser, ArgAction, ArgMatches, Command};
|
||||
use hurl::runner::RunnerOptionsBuilder;
|
||||
use hurl_core::ast::Entry;
|
||||
|
||||
use crate::cli;
|
||||
use crate::cli::CliError;
|
||||
use crate::http::{ClientOptions, ContextDir};
|
||||
use crate::runner::{RunnerOptions, Value, Verbosity};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CliOptions {
|
||||
pub cacert_file: Option<String>,
|
||||
@ -82,18 +79,10 @@ pub enum OutputType {
|
||||
}
|
||||
|
||||
pub fn app(version: &str) -> Command {
|
||||
let ClientOptions {
|
||||
connect_timeout: default_connect_timeout,
|
||||
max_redirect: default_max_redirect,
|
||||
retry_max_count: default_retry_max_count,
|
||||
timeout: default_timeout,
|
||||
..
|
||||
} = ClientOptions::default();
|
||||
|
||||
let default_connect_timeout = default_connect_timeout.as_secs();
|
||||
let default_max_redirect = default_max_redirect.unwrap();
|
||||
let default_timeout = default_timeout.as_secs();
|
||||
let default_retry_max_count = default_retry_max_count.unwrap();
|
||||
let default_connect_timeout = Duration::from_secs(300);
|
||||
let default_max_redirect = 50;
|
||||
let default_timeout = Duration::from_secs(300);
|
||||
let default_retry_max_count = 10;
|
||||
|
||||
Command::new("hurl")
|
||||
.about("Run Hurl file(s) or standard input")
|
||||
@ -145,7 +134,7 @@ pub fn app(version: &str) -> Command {
|
||||
.long("connect-timeout")
|
||||
.value_name("SECONDS")
|
||||
.help("Maximum time allowed for connection")
|
||||
.default_value(default_connect_timeout.to_string())
|
||||
.default_value(default_connect_timeout.as_secs().to_string())
|
||||
.value_parser(value_parser!(u64))
|
||||
.num_args(1)
|
||||
)
|
||||
@ -252,7 +241,7 @@ pub fn app(version: &str) -> Command {
|
||||
.short('m')
|
||||
.value_name("SECONDS")
|
||||
.help("Maximum time allowed for the transfer")
|
||||
.default_value(default_timeout.to_string())
|
||||
.default_value(default_timeout.as_secs().to_string())
|
||||
.allow_hyphen_values(true)
|
||||
.value_parser(value_parser!(u64))
|
||||
.num_args(1)
|
||||
|
@ -30,8 +30,9 @@ use super::request_spec::*;
|
||||
use super::response::*;
|
||||
use super::{Header, HttpError, Verbosity};
|
||||
use crate::http::certificate::Certificate;
|
||||
use crate::http::{easy_ext, ContextDir};
|
||||
use crate::http::easy_ext;
|
||||
use crate::util::logger::Logger;
|
||||
use crate::util::path::ContextDir;
|
||||
use base64::engine::general_purpose;
|
||||
use base64::Engine;
|
||||
use curl::easy::{List, SslOpt};
|
||||
|
@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Hurl (https://hurl.dev)
|
||||
* Copyright (C) 2023 Orange
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use crate::util::path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Represents the directories used to run a Hurl file.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ContextDir {
|
||||
/// The current working directory.
|
||||
/// If current directory is a relative path, the `is_allowed` is not guaranteed to be correct.
|
||||
current_dir: PathBuf,
|
||||
/// The file root, either inferred or explicitly positioned by the user.
|
||||
/// As a consequence, it is always defined (and can't be replaced by a `Option<PathBuf>`).
|
||||
/// It can be relative (to the current directory) or absolute.
|
||||
file_root: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for ContextDir {
|
||||
fn default() -> Self {
|
||||
ContextDir {
|
||||
current_dir: PathBuf::new(),
|
||||
file_root: PathBuf::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContextDir {
|
||||
/// Returns a context directory with the given current directory and file root.
|
||||
pub fn new(current_dir: &Path, file_root: &Path) -> ContextDir {
|
||||
ContextDir {
|
||||
current_dir: PathBuf::from(current_dir),
|
||||
file_root: PathBuf::from(file_root),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a path (absolute or relative), given a filename.
|
||||
pub fn get_path(&self, filename: &str) -> PathBuf {
|
||||
self.file_root.join(Path::new(filename))
|
||||
}
|
||||
|
||||
/// Checks if a given filename access is authorized.
|
||||
/// This method is used to check if a local file can be included in POST request.
|
||||
pub fn is_access_allowed(&self, filename: &str) -> bool {
|
||||
let file = self.get_path(filename);
|
||||
let absolute_file = self.current_dir.join(file);
|
||||
let absolute_file_root = self.current_dir.join(&self.file_root);
|
||||
path::is_descendant(absolute_file.as_path(), absolute_file_root.as_path())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::http::ContextDir;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_without_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_with_explicit_absolute_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl --file-root /file test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("/file");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin")); // absolute path is /file/foo.bin
|
||||
assert!(context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("../file");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_with_implicit_relative_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl a/b/test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("a/b");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("c/foo.bin")); // absolute path is /tmp/a/b/c/foo.bin
|
||||
assert!(context_dir.is_access_allowed("/tmp/a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/tmp/a/b/c/d/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_with_explicit_relative_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl --file-root ../tmp test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("../tmp");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
}
|
||||
}
|
@ -18,24 +18,20 @@
|
||||
|
||||
pub use self::certificate::Certificate;
|
||||
pub use self::client::Client;
|
||||
pub use self::context_dir::ContextDir;
|
||||
pub use self::cookie::{CookieAttribute, ResponseCookie};
|
||||
pub use self::core::{Cookie, Param, RequestCookie};
|
||||
pub use self::error::HttpError;
|
||||
pub use self::header::Header;
|
||||
pub use self::options::{ClientOptions, Verbosity};
|
||||
pub use self::request::Request;
|
||||
#[cfg(test)]
|
||||
pub use self::request_spec::tests::*;
|
||||
pub use self::request_spec::{Body, FileParam, Method, MultipartParam, RequestSpec};
|
||||
#[cfg(test)]
|
||||
pub use self::response::tests::*;
|
||||
pub use self::response::{Response, Version};
|
||||
#[cfg(test)]
|
||||
pub use self::tests::*;
|
||||
pub use self::version::libcurl_version_info;
|
||||
|
||||
mod certificate;
|
||||
mod client;
|
||||
mod context_dir;
|
||||
mod cookie;
|
||||
mod core;
|
||||
mod debug;
|
||||
|
@ -101,11 +101,11 @@ fn parse_cookie(s: &str) -> RequestCookie {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::RequestCookie;
|
||||
|
||||
pub fn hello_request() -> Request {
|
||||
fn hello_request() -> Request {
|
||||
Request {
|
||||
method: "GET".to_string(),
|
||||
url: "http://localhost:8000/hello".to_string(),
|
||||
@ -118,7 +118,7 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query_string_request() -> Request {
|
||||
fn query_string_request() -> Request {
|
||||
Request {
|
||||
method: "GET".to_string(),
|
||||
url: "http://localhost:8000/querystring-params?param1=value1¶m2=¶m3=a%3Db¶m4=1%2C2%2C3".to_string(),
|
||||
@ -127,7 +127,7 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cookies_request() -> Request {
|
||||
fn cookies_request() -> Request {
|
||||
Request {
|
||||
method: "GET".to_string(),
|
||||
url: "http://localhost:8000/cookies".to_string(),
|
||||
|
@ -150,79 +150,3 @@ impl fmt::Display for FileParam {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
pub fn hello_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Get,
|
||||
url: "http://localhost:8000/hello".to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn custom_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Get,
|
||||
url: "http://localhost/custom".to_string(),
|
||||
headers: vec![
|
||||
Header::new("User-Agent", "iPhone"),
|
||||
Header::new("Foo", "Bar"),
|
||||
],
|
||||
cookies: vec![
|
||||
RequestCookie {
|
||||
name: String::from("theme"),
|
||||
value: String::from("light"),
|
||||
},
|
||||
RequestCookie {
|
||||
name: String::from("sessionToken"),
|
||||
value: String::from("abc123"),
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Get,
|
||||
url: "http://localhost:8000/querystring-params".to_string(),
|
||||
querystring: vec![
|
||||
Param {
|
||||
name: String::from("param1"),
|
||||
value: String::from("value1"),
|
||||
},
|
||||
Param {
|
||||
name: String::from("param2"),
|
||||
value: String::from("a b"),
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn form_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Post,
|
||||
url: "http://localhost/form-params".to_string(),
|
||||
headers: vec![Header::new(
|
||||
"Content-Type",
|
||||
"application/x-www-form-urlencoded",
|
||||
)],
|
||||
form: vec![
|
||||
Param {
|
||||
name: String::from("param1"),
|
||||
value: String::from("value1"),
|
||||
},
|
||||
Param {
|
||||
name: String::from("param2"),
|
||||
value: String::from("a b"),
|
||||
},
|
||||
],
|
||||
content_type: Some("multipart/form-data".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use super::core::*;
|
||||
use super::RequestSpec;
|
||||
use crate::http::*;
|
||||
use crate::util::path::ContextDir;
|
||||
use std::collections::HashMap;
|
||||
|
||||
impl RequestSpec {
|
||||
@ -235,8 +235,32 @@ fn escape_string(s: &str) -> String {
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::http;
|
||||
use std::path::Path;
|
||||
|
||||
fn form_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Post,
|
||||
url: "http://localhost/form-params".to_string(),
|
||||
headers: vec![Header::new(
|
||||
"Content-Type",
|
||||
"application/x-www-form-urlencoded",
|
||||
)],
|
||||
form: vec![
|
||||
Param {
|
||||
name: String::from("param1"),
|
||||
value: String::from("value1"),
|
||||
},
|
||||
Param {
|
||||
name: String::from("param2"),
|
||||
value: String::from("a b"),
|
||||
},
|
||||
],
|
||||
content_type: Some("multipart/form-data".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_byte() {
|
||||
assert_eq!(encode_byte(1), "\\x01".to_string());
|
||||
@ -322,7 +346,7 @@ pub mod tests {
|
||||
fn requests_curl_args() {
|
||||
let context_dir = &ContextDir::default();
|
||||
assert_eq!(
|
||||
hello_http_request().curl_args(context_dir),
|
||||
http::hello_http_request().curl_args(context_dir),
|
||||
vec!["'http://localhost:8000/hello'".to_string()]
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -81,117 +81,9 @@ impl Response {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
pub fn hello_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(String::from("Hello World!")),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn html_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![Header::new("Content-Type", "text/html; charset=utf-8")],
|
||||
body: String::into_bytes(String::from(
|
||||
"<html><head><meta charset=\"UTF-8\"></head><body><br></body></html>",
|
||||
)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xml_invalid_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
xxx
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xml_two_users_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
<?xml version="1.0"?>
|
||||
<users>
|
||||
<user id="1">Bob</user>
|
||||
<user id="2">Bill</user>
|
||||
</users>
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xml_three_users_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
<?xml version="1.0"?>
|
||||
<users>
|
||||
<user id="1">Bob</user>
|
||||
<user id="2">Bill</user>
|
||||
<user id="3">Bruce</user>
|
||||
</users>
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn json_http_response() -> Response {
|
||||
Response {
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
{
|
||||
"success":false,
|
||||
"errors": [
|
||||
{ "id": "error1"},
|
||||
{"id": "error2"}
|
||||
],
|
||||
"duration": 1.5
|
||||
}
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "application/octet-stream"),
|
||||
Header::new("Content-Length", "1"),
|
||||
],
|
||||
body: vec![255],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_header_values() {
|
||||
let response = Response {
|
||||
|
@ -22,6 +22,7 @@ use std::time::Duration;
|
||||
|
||||
use crate::http::*;
|
||||
use crate::util::logger::LoggerBuilder;
|
||||
use crate::util::path::ContextDir;
|
||||
|
||||
fn default_get_request(url: &str) -> RequestSpec {
|
||||
RequestSpec {
|
||||
|
@ -15,5 +15,149 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use crate::http::{Header, Method, Param, RequestCookie, RequestSpec, Response};
|
||||
|
||||
mod libcurl;
|
||||
mod runner;
|
||||
mod runner;
|
||||
|
||||
/// Some Request Response to be used by tests
|
||||
|
||||
pub fn hello_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Get,
|
||||
url: "http://localhost:8000/hello".to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn json_http_response() -> Response {
|
||||
Response {
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
{
|
||||
"success":false,
|
||||
"errors": [
|
||||
{ "id": "error1"},
|
||||
{"id": "error2"}
|
||||
],
|
||||
"duration": 1.5
|
||||
}
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xml_two_users_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
<?xml version="1.0"?>
|
||||
<users>
|
||||
<user id="1">Bob</user>
|
||||
<user id="2">Bill</user>
|
||||
</users>
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xml_three_users_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
<?xml version="1.0"?>
|
||||
<users>
|
||||
<user id="1">Bob</user>
|
||||
<user id="2">Bill</user>
|
||||
<user id="3">Bruce</user>
|
||||
</users>
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hello_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
body: String::into_bytes(String::from("Hello World!")),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "application/octet-stream"),
|
||||
Header::new("Content-Length", "1"),
|
||||
],
|
||||
body: vec![255],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn html_http_response() -> Response {
|
||||
Response {
|
||||
headers: vec![Header::new("Content-Type", "text/html; charset=utf-8")],
|
||||
body: String::into_bytes(String::from(
|
||||
"<html><head><meta charset=\"UTF-8\"></head><body><br></body></html>",
|
||||
)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Get,
|
||||
url: "http://localhost:8000/querystring-params".to_string(),
|
||||
querystring: vec![
|
||||
Param {
|
||||
name: String::from("param1"),
|
||||
value: String::from("value1"),
|
||||
},
|
||||
Param {
|
||||
name: String::from("param2"),
|
||||
value: String::from("a b"),
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn custom_http_request() -> RequestSpec {
|
||||
RequestSpec {
|
||||
method: Method::Get,
|
||||
url: "http://localhost/custom".to_string(),
|
||||
headers: vec![
|
||||
Header::new("User-Agent", "iPhone"),
|
||||
Header::new("Foo", "Bar"),
|
||||
],
|
||||
cookies: vec![
|
||||
RequestCookie {
|
||||
name: String::from("theme"),
|
||||
value: String::from("light"),
|
||||
},
|
||||
RequestCookie {
|
||||
name: String::from("sessionToken"),
|
||||
value: String::from("abc123"),
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,11 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use hurl_core::ast::*;
|
||||
use crate::{http, runner};
|
||||
use crate::runner;
|
||||
use crate::runner::RunnerOptions;
|
||||
use crate::util::logger::LoggerBuilder;
|
||||
use hurl_core::ast::*;
|
||||
|
||||
#[cfg(test)]
|
||||
fn hello_request() -> Request {
|
||||
// GET http://localhost;8000/hello
|
||||
let source_info = SourceInfo {
|
||||
@ -86,8 +85,6 @@ fn hello_request() -> Request {
|
||||
|
||||
#[test]
|
||||
fn test_hello() {
|
||||
let mut client = http::Client::new(None);
|
||||
|
||||
// We construct a Hurl file ast "by hand", with fake source info.
|
||||
// In this particular case, the raw content is empty as the Hurl file hasn't
|
||||
// been built from a text content.
|
||||
@ -138,7 +135,6 @@ fn test_hello() {
|
||||
&hurl_file,
|
||||
content,
|
||||
filename,
|
||||
&mut client,
|
||||
&runner_options,
|
||||
&variables,
|
||||
&logger,
|
||||
|
@ -18,10 +18,11 @@
|
||||
#![cfg_attr(feature = "strict", deny(warnings))]
|
||||
|
||||
mod html;
|
||||
pub mod http;
|
||||
mod http;
|
||||
mod json;
|
||||
mod jsonpath;
|
||||
pub mod output;
|
||||
pub mod report;
|
||||
pub mod runner;
|
||||
pub mod util;
|
||||
pub use http::libcurl_version_info;
|
||||
|
@ -31,7 +31,7 @@ use hurl::report::html;
|
||||
use hurl::runner;
|
||||
use hurl::runner::HurlResult;
|
||||
use hurl::util::logger::{BaseLogger, Logger, LoggerBuilder};
|
||||
use hurl::{http, output};
|
||||
use hurl::{libcurl_version_info, output};
|
||||
use hurl_core::ast::HurlFile;
|
||||
use hurl_core::parser;
|
||||
use report::junit;
|
||||
@ -58,7 +58,7 @@ pub struct HurlRun {
|
||||
fn main() {
|
||||
init_colored();
|
||||
|
||||
let libcurl_version = http::libcurl_version_info();
|
||||
let libcurl_version = libcurl_version_info();
|
||||
let version_info = format!(
|
||||
"{} {}\nFeatures (libcurl): {}\nFeatures (built-in): brotli",
|
||||
clap::crate_version!(),
|
||||
@ -216,15 +216,12 @@ fn execute(
|
||||
log_run_info(hurl_file, cli_options, logger);
|
||||
|
||||
let variables = &cli_options.variables;
|
||||
let cookie_input_file = cli_options.cookie_input_file.clone();
|
||||
let runner_options = cli_options.to(filename, current_dir);
|
||||
let mut client = http::Client::new(cookie_input_file);
|
||||
|
||||
runner::run(
|
||||
hurl_file,
|
||||
content,
|
||||
filename,
|
||||
&mut client,
|
||||
&runner_options,
|
||||
variables,
|
||||
logger,
|
||||
|
@ -179,10 +179,10 @@ pub fn eval_assert(
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use hurl_core::ast::SourceInfo;
|
||||
|
||||
use super::super::query;
|
||||
use super::*;
|
||||
use crate::http::xml_three_users_http_response;
|
||||
use hurl_core::ast::SourceInfo;
|
||||
|
||||
// xpath //user countEquals 3
|
||||
pub fn assert_count_user() -> Assert {
|
||||
@ -226,7 +226,7 @@ pub mod tests {
|
||||
eval_assert(
|
||||
&assert_count_user(),
|
||||
&variables,
|
||||
&http::xml_three_users_http_response()
|
||||
&xml_three_users_http_response(),
|
||||
),
|
||||
AssertResult::Explicit {
|
||||
actual: Ok(Some(Value::Nodeset(3))),
|
||||
|
@ -15,19 +15,16 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use hurl_core::ast::*;
|
||||
|
||||
use super::core::{Error, RunnerError};
|
||||
use super::json::eval_json_value;
|
||||
use super::value::Value;
|
||||
use crate::http;
|
||||
use crate::http::ContextDir;
|
||||
use crate::runner::multiline::eval_multiline;
|
||||
use crate::runner::template::eval_template;
|
||||
use crate::util::path::ContextDir;
|
||||
use hurl_core::ast::*;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn eval_body(
|
||||
body: &Body,
|
||||
|
@ -57,11 +57,9 @@ pub fn eval_capture(
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use hurl_core::ast::{Pos, SourceInfo};
|
||||
|
||||
use super::*;
|
||||
|
||||
use self::super::super::query;
|
||||
use super::*;
|
||||
use hurl_core::ast::{Pos, SourceInfo};
|
||||
|
||||
pub fn user_count_capture() -> Capture {
|
||||
// non scalar value
|
||||
|
@ -29,8 +29,8 @@ use crate::util::logger::LoggerBuilder;
|
||||
use hurl_core::ast::VersionValue::VersionAnyLegacy;
|
||||
use hurl_core::ast::*;
|
||||
|
||||
/// Runs a `hurl_file`, issue from the given `content`and `filename`, with
|
||||
/// an `http_client`. Returns a [`HurlResult`] upon completion.
|
||||
/// Runs a `hurl_file`, issue from the given `content`and `filename` and
|
||||
/// returns a [`HurlResult`] upon completion.
|
||||
///
|
||||
/// `filename` and `content` are used to display rich logs (for parsing error or asserts
|
||||
/// failures).
|
||||
@ -41,13 +41,11 @@ use hurl_core::ast::*;
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::path::PathBuf;
|
||||
/// use hurl_core::parser;
|
||||
/// use hurl::http;
|
||||
/// use hurl::http::ContextDir;
|
||||
/// use hurl::runner;
|
||||
/// use hurl::runner::{Value, RunnerOptionsBuilder, Verbosity};
|
||||
/// use hurl::util::logger::LoggerBuilder;
|
||||
///
|
||||
/// // Parse Hurl file
|
||||
/// // Parse the Hurl file
|
||||
/// let filename = "sample.hurl";
|
||||
/// let content = r#"
|
||||
/// GET http://localhost:8000/hello
|
||||
@ -55,8 +53,6 @@ use hurl_core::ast::*;
|
||||
/// "#;
|
||||
/// let hurl_file = parser::parse_hurl_file(content).unwrap();
|
||||
///
|
||||
/// // Create an HTTP client
|
||||
/// let mut client = http::Client::new(None);
|
||||
/// let logger = LoggerBuilder::new().build();
|
||||
///
|
||||
/// // Define runner options
|
||||
@ -69,12 +65,11 @@ use hurl_core::ast::*;
|
||||
/// let mut variables = HashMap::default();
|
||||
/// variables.insert("name".to_string(), Value::String("toto".to_string()));
|
||||
///
|
||||
/// // Run the hurl file
|
||||
/// // Run the Hurl file
|
||||
/// let hurl_results = runner::run(
|
||||
/// &hurl_file,
|
||||
/// content,
|
||||
/// filename,
|
||||
/// &mut client,
|
||||
/// &runner_options,
|
||||
/// &variables,
|
||||
/// &logger
|
||||
@ -85,11 +80,12 @@ pub fn run(
|
||||
hurl_file: &HurlFile,
|
||||
content: &str,
|
||||
filename: &str,
|
||||
http_client: &mut http::Client,
|
||||
runner_options: &RunnerOptions,
|
||||
variables: &HashMap<String, Value>,
|
||||
logger: &Logger,
|
||||
) -> HurlResult {
|
||||
let cookie_input_file = runner_options.cookie_input_file.clone();
|
||||
let mut http_client = http::Client::new(cookie_input_file);
|
||||
let mut entries = vec![];
|
||||
let mut variables = variables.clone();
|
||||
let mut entry_index = 1;
|
||||
@ -140,7 +136,7 @@ pub fn run(
|
||||
Ok(options) => entry::run(
|
||||
entry,
|
||||
entry_index,
|
||||
http_client,
|
||||
&mut http_client,
|
||||
&mut variables,
|
||||
options,
|
||||
&logger,
|
||||
|
@ -15,20 +15,16 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
#[allow(unused)]
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::http;
|
||||
use crate::http::ContextDir;
|
||||
use crate::runner::body::eval_file;
|
||||
use hurl_core::ast::*;
|
||||
|
||||
use super::core::Error;
|
||||
use super::template::eval_template;
|
||||
use super::value::Value;
|
||||
use crate::http;
|
||||
use crate::runner::body::eval_file;
|
||||
use crate::util::path::ContextDir;
|
||||
use hurl_core::ast::*;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn eval_multipart_param(
|
||||
multipart_param: &MultipartParam,
|
||||
|
@ -449,24 +449,6 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn json_http_response() -> http::Response {
|
||||
http::Response {
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
{
|
||||
"success":false,
|
||||
"errors": [
|
||||
{ "id": "error1"},
|
||||
{"id": "error2"}
|
||||
]
|
||||
}
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jsonpath_success() -> Query {
|
||||
// jsonpath $.success
|
||||
Query {
|
||||
@ -1016,7 +998,7 @@ pub mod tests {
|
||||
},
|
||||
};
|
||||
|
||||
let error = eval_query(&jsonpath_query, &variables, &json_http_response())
|
||||
let error = eval_query(&jsonpath_query, &variables, &http::json_http_response())
|
||||
.err()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
@ -1066,13 +1048,13 @@ pub mod tests {
|
||||
fn test_query_json() {
|
||||
let variables = HashMap::new();
|
||||
assert_eq!(
|
||||
eval_query(&jsonpath_success(), &variables, &json_http_response())
|
||||
eval_query(&jsonpath_success(), &variables, &http::json_http_response())
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
Value::Bool(false)
|
||||
);
|
||||
assert_eq!(
|
||||
eval_query(&jsonpath_errors(), &variables, &json_http_response())
|
||||
eval_query(&jsonpath_errors(), &variables, &http::json_http_response())
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
Value::List(vec![
|
||||
|
@ -15,22 +15,17 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use base64::engine::general_purpose;
|
||||
use base64::Engine;
|
||||
use std::collections::HashMap;
|
||||
#[allow(unused)]
|
||||
use std::io::prelude::*;
|
||||
|
||||
use crate::http;
|
||||
use crate::http::ContextDir;
|
||||
use hurl_core::ast::*;
|
||||
|
||||
use super::body::eval_body;
|
||||
use super::core::Error;
|
||||
use super::template::eval_template;
|
||||
use super::value::Value;
|
||||
use crate::http;
|
||||
use crate::runner::multipart::eval_multipart_param;
|
||||
use crate::util::path::ContextDir;
|
||||
use base64::engine::general_purpose;
|
||||
use base64::Engine;
|
||||
use hurl_core::ast::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Transforms an AST `request` to a spec request given a set of `variables`.
|
||||
pub fn eval_request(
|
||||
@ -186,19 +181,18 @@ fn eval_method(method: &Method) -> http::Method {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hurl_core::ast::SourceInfo;
|
||||
|
||||
use super::super::core::RunnerError;
|
||||
use super::*;
|
||||
use hurl_core::ast::SourceInfo;
|
||||
|
||||
pub fn whitespace() -> Whitespace {
|
||||
fn whitespace() -> Whitespace {
|
||||
Whitespace {
|
||||
value: String::from(" "),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hello_request() -> Request {
|
||||
fn hello_request() -> Request {
|
||||
let line_terminator = LineTerminator {
|
||||
space0: whitespace(),
|
||||
comment: None,
|
||||
@ -235,7 +229,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simple_key_value(key: EncodedString, value: Template) -> KeyValue {
|
||||
fn simple_key_value(key: EncodedString, value: Template) -> KeyValue {
|
||||
let line_terminator = LineTerminator {
|
||||
space0: whitespace(),
|
||||
comment: None,
|
||||
@ -252,7 +246,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query_request() -> Request {
|
||||
fn query_request() -> Request {
|
||||
let line_terminator = LineTerminator {
|
||||
space0: whitespace(),
|
||||
comment: None,
|
||||
@ -323,7 +317,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_error_variable() {
|
||||
fn test_error_variable() {
|
||||
let variables = HashMap::new();
|
||||
let error = eval_request(&hello_request(), &variables, &ContextDir::default())
|
||||
.err()
|
||||
@ -338,7 +332,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hello_request() {
|
||||
fn test_hello_request() {
|
||||
let mut variables = HashMap::new();
|
||||
variables.insert(
|
||||
String::from("base_url"),
|
||||
@ -350,7 +344,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_query_request() {
|
||||
fn test_query_request() {
|
||||
let mut variables = HashMap::new();
|
||||
variables.insert(
|
||||
String::from("param1"),
|
||||
|
@ -15,13 +15,6 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::http;
|
||||
use crate::http::ContextDir;
|
||||
use crate::runner::multiline::eval_multiline;
|
||||
use hurl_core::ast::*;
|
||||
|
||||
use super::assert::eval_assert;
|
||||
use super::body::eval_body;
|
||||
use super::capture::eval_capture;
|
||||
@ -29,6 +22,11 @@ use super::core::*;
|
||||
use super::json::eval_json_value;
|
||||
use super::template::eval_template;
|
||||
use super::value::Value;
|
||||
use crate::http;
|
||||
use crate::runner::multiline::eval_multiline;
|
||||
use crate::util::path::ContextDir;
|
||||
use hurl_core::ast::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Returns a list of assert results on the response status code and HTTP version,
|
||||
/// given a set of `variables`, an actual `http_response` and a spec `response`.
|
||||
|
@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use crate::http::ContextDir;
|
||||
use crate::runner::Verbosity;
|
||||
use crate::util::path::ContextDir;
|
||||
use hurl_core::ast::Entry;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -17,8 +17,53 @@
|
||||
*/
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
/// Represents the directories used to run a Hurl file.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ContextDir {
|
||||
/// The current working directory.
|
||||
/// If current directory is a relative path, the `is_allowed` is not guaranteed to be correct.
|
||||
current_dir: PathBuf,
|
||||
/// The file root, either inferred or explicitly positioned by the user.
|
||||
/// As a consequence, it is always defined (and can't be replaced by a `Option<PathBuf>`).
|
||||
/// It can be relative (to the current directory) or absolute.
|
||||
file_root: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for ContextDir {
|
||||
fn default() -> Self {
|
||||
ContextDir {
|
||||
current_dir: PathBuf::new(),
|
||||
file_root: PathBuf::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContextDir {
|
||||
/// Returns a context directory with the given current directory and file root.
|
||||
pub fn new(current_dir: &Path, file_root: &Path) -> ContextDir {
|
||||
ContextDir {
|
||||
current_dir: PathBuf::from(current_dir),
|
||||
file_root: PathBuf::from(file_root),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a path (absolute or relative), given a filename.
|
||||
pub fn get_path(&self, filename: &str) -> PathBuf {
|
||||
self.file_root.join(Path::new(filename))
|
||||
}
|
||||
|
||||
/// Checks if a given filename access is authorized.
|
||||
/// This method is used to check if a local file can be included in POST request.
|
||||
pub fn is_access_allowed(&self, filename: &str) -> bool {
|
||||
let file = self.get_path(filename);
|
||||
let absolute_file = self.current_dir.join(file);
|
||||
let absolute_file_root = self.current_dir.join(&self.file_root);
|
||||
is_descendant(absolute_file.as_path(), absolute_file_root.as_path())
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if `path` is a descendant path of `ancestor`, false otherwise.
|
||||
pub fn is_descendant(path: &Path, ancestor: &Path) -> bool {
|
||||
fn is_descendant(path: &Path, ancestor: &Path) -> bool {
|
||||
let path = normalize_path(path);
|
||||
let ancestor = normalize_path(ancestor);
|
||||
for a in path.ancestors() {
|
||||
@ -65,6 +110,105 @@ fn normalize_path(path: &Path) -> PathBuf {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_without_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_with_explicit_absolute_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl --file-root /file test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("/file");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin")); // absolute path is /file/foo.bin
|
||||
assert!(context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("../file");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_with_implicit_relative_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl a/b/test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("a/b");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("c/foo.bin")); // absolute path is /tmp/a/b/c/foo.bin
|
||||
assert!(context_dir.is_access_allowed("/tmp/a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/tmp/a/b/c/d/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_filename_allowed_access_with_explicit_relative_user_file_root() {
|
||||
// ```
|
||||
// $ cd /tmp
|
||||
// $ hurl --file-root ../tmp test.hurl
|
||||
// ```
|
||||
let current_dir = Path::new("/tmp");
|
||||
let file_root = Path::new("../tmp");
|
||||
let context_dir = ContextDir::new(current_dir, file_root);
|
||||
assert!(context_dir.is_access_allowed("foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("/tmp/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../tmp/a/b/foo.bin"));
|
||||
assert!(context_dir.is_access_allowed("../../../tmp/a/b/foo.bin"));
|
||||
|
||||
assert!(!context_dir.is_access_allowed("/file/foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../foo.bin"));
|
||||
assert!(!context_dir.is_access_allowed("../../file/foo.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_descendant_true() {
|
||||
let child = Path::new("/tmp/foo/bar.txt");
|
||||
|
Loading…
Reference in New Issue
Block a user