diff --git a/README.md b/README.md index ad786849e..a2b8b811e 100644 --- a/README.md +++ b/README.md @@ -976,6 +976,7 @@ will follow a redirection only for the second entry. | --key <KEY> | Private key file name.
| | -L, --location | Follow redirect. To limit the amount of redirects to follow use the [`--max-redirs`](#max-redirs) option
| | --location-trusted | Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to.
This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).
| +| --max-filesize <BYTES> | Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer does not start.
| | --max-redirs <NUM> | Set maximum number of redirection-followings allowed

By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.
| | -m, --max-time <SECONDS> | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.

See also [`--connect-timeout`](#connect-timeout).

This is a cli-only option.
| | -n, --netrc | Scan the .netrc file in the user's home directory for the username and password.

See also [`--netrc-file`](#netrc-file) and [`--netrc-optional`](#netrc-optional).
| diff --git a/completions/_hurl b/completions/_hurl index e8b9d7d7b..acc088743 100644 --- a/completions/_hurl +++ b/completions/_hurl @@ -46,6 +46,7 @@ _hurl() { '(-6 --ipv6)'{-6,--ipv6}'[Tell Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4]' \ '--jobs[(Experimental) Maximum number of parallel jobs]: :' \ '--json[Output each Hurl file result to JSON]' \ + '--max-filesize[Specify the maximum size (in bytes) of a file to download]: :' \ '--max-redirs[Maximum number of redirects allowed, -1 for unlimited redirects]: :' \ '(-m --max-time)'{-m,--max-time}'[Maximum time allowed for the transfer]: :' \ '(-n --netrc)'{-n,--netrc}'[Must read .netrc for username and password]' \ diff --git a/completions/_hurl.ps1 b/completions/_hurl.ps1 index a24d2cca9..c85617be9 100644 --- a/completions/_hurl.ps1 +++ b/completions/_hurl.ps1 @@ -51,6 +51,7 @@ Register-ArgumentCompleter -Native -CommandName 'hurl' -ScriptBlock { [CompletionResult]::new('--ipv6', 'ipv6', [CompletionResultType]::ParameterName, 'Tell Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4') [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, '(Experimental) Maximum number of parallel jobs') [CompletionResult]::new('--json', 'json', [CompletionResultType]::ParameterName, 'Output each Hurl file result to JSON') + [CompletionResult]::new('--max-filesize', 'max-filesize', [CompletionResultType]::ParameterName, 'Specify the maximum size (in bytes) of a file to download') [CompletionResult]::new('--max-redirs', 'max-redirs', [CompletionResultType]::ParameterName, 'Maximum number of redirects allowed, -1 for unlimited redirects') [CompletionResult]::new('--max-time', 'max-time', [CompletionResultType]::ParameterName, 'Maximum time allowed for the transfer') [CompletionResult]::new('--netrc', 'netrc', [CompletionResultType]::ParameterName, 'Must read .netrc for username and password') diff --git a/completions/hurl.bash b/completions/hurl.bash index 7fb1dd12d..36f705302 100644 --- a/completions/hurl.bash +++ b/completions/hurl.bash @@ -5,7 +5,7 @@ _hurl() _init_completion || return if [[ $cur == -* ]]; then - COMPREPLY=($(compgen -W '--aws-sigv4 --cacert --cert --key --color --compressed --connect-timeout --connect-to --continue-on-error --cookie --cookie-jar --delay --error-format --fail-at-end --file-root --location --location-trusted --from-entry --glob --http1.0 --http1.1 --http2 --http3 --ignore-asserts --include --insecure --interactive --ipv4 --ipv6 --jobs --json --max-redirs --max-time --netrc --netrc-file --netrc-optional --no-color --no-output --noproxy --output --parallel --path-as-is --proxy --report-html --report-junit --report-tap --resolve --retry --retry-interval --ssl-no-revoke --test --to-entry --unix-socket --user --user-agent --variable --variables-file --verbose --very-verbose --help --version' -- "$cur")) + COMPREPLY=($(compgen -W '--aws-sigv4 --cacert --cert --key --color --compressed --connect-timeout --connect-to --continue-on-error --cookie --cookie-jar --delay --error-format --fail-at-end --file-root --location --location-trusted --from-entry --glob --http1.0 --http1.1 --http2 --http3 --ignore-asserts --include --insecure --interactive --ipv4 --ipv6 --jobs --json --max-filesize --max-redirs --max-time --netrc --netrc-file --netrc-optional --no-color --no-output --noproxy --output --parallel --path-as-is --proxy --report-html --report-junit --report-tap --resolve --retry --retry-interval --ssl-no-revoke --test --to-entry --unix-socket --user --user-agent --variable --variables-file --verbose --very-verbose --help --version' -- "$cur")) return fi diff --git a/completions/hurl.fish b/completions/hurl.fish index 0111fe5ec..2657e3e61 100644 --- a/completions/hurl.fish +++ b/completions/hurl.fish @@ -29,6 +29,7 @@ complete -c hurl -l ipv4 -d 'Tell Hurl to use IPv4 addresses only when resolving complete -c hurl -l ipv6 -d 'Tell Hurl to use IPv6 addresses only when resolving host names, and not for example try IPv4' complete -c hurl -l jobs -d '(Experimental) Maximum number of parallel jobs' complete -c hurl -l json -d 'Output each Hurl file result to JSON' +complete -c hurl -l max-filesize -d 'Specify the maximum size (in bytes) of a file to download' complete -c hurl -l max-redirs -d 'Maximum number of redirects allowed, -1 for unlimited redirects' complete -c hurl -l max-time -d 'Maximum time allowed for the transfer' complete -c hurl -l netrc -d 'Must read .netrc for username and password' diff --git a/docs/manual.md b/docs/manual.md index def49f0d2..fbbbdfb24 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -177,6 +177,7 @@ will follow a redirection only for the second entry. | --key <KEY> | Private key file name.
| | -L, --location | Follow redirect. To limit the amount of redirects to follow use the [`--max-redirs`](#max-redirs) option
| | --location-trusted | Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to.
This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).
| +| --max-filesize <BYTES> | Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer does not start.
| | --max-redirs <NUM> | Set maximum number of redirection-followings allowed

By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.
| | -m, --max-time <SECONDS> | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.

See also [`--connect-timeout`](#connect-timeout).

This is a cli-only option.
| | -n, --netrc | Scan the .netrc file in the user's home directory for the username and password.

See also [`--netrc-file`](#netrc-file) and [`--netrc-optional`](#netrc-optional).
| diff --git a/docs/manual/hurl.1 b/docs/manual/hurl.1 index 199e1d7a8..99a6a3815 100644 --- a/docs/manual/hurl.1 +++ b/docs/manual/hurl.1 @@ -1,4 +1,4 @@ -.TH hurl 1 "26 Mar 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" +.TH hurl 1 "01 Apr 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" .SH NAME hurl - run and test HTTP requests. @@ -295,6 +295,10 @@ Follow redirect. To limit the amount of redirects to follow use the \fI--max-red Like \fI-L, --location\fP, but allows sending the name + password to all hosts that the site may redirect to. This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication). +.IP "--max-filesize " + +Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer does not start. + .IP "--max-redirs " Set maximum number of redirection-followings allowed diff --git a/docs/manual/hurl.md b/docs/manual/hurl.md index 590b6ac9d..8d7b924f2 100644 --- a/docs/manual/hurl.md +++ b/docs/manual/hurl.md @@ -314,6 +314,10 @@ Follow redirect. To limit the amount of redirects to follow use the [`--max-redi Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to. This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication). +### --max-filesize {#max-filesize} + +Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer does not start. + ### --max-redirs {#max-redirs} Set maximum number of redirection-followings allowed diff --git a/docs/manual/hurlfmt.1 b/docs/manual/hurlfmt.1 index 3c2f664ed..e9f528efb 100644 --- a/docs/manual/hurlfmt.1 +++ b/docs/manual/hurlfmt.1 @@ -1,4 +1,4 @@ -.TH hurl 1 "26 Mar 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" +.TH hurl 1 "01 Apr 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" .SH NAME hurlfmt - format Hurl files diff --git a/docs/spec/options/hurl/max_filesize.option b/docs/spec/options/hurl/max_filesize.option new file mode 100644 index 000000000..52ddf7da3 --- /dev/null +++ b/docs/spec/options/hurl/max_filesize.option @@ -0,0 +1,7 @@ +name: max_filesize +long: max-filesize +value: BYTES +value_parser: clap::value_parser!(u64) +help: Specify the maximum size (in bytes) of a file to download +--- +Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer does not start. diff --git a/integration/hurl/tests_ok/help.out.pattern b/integration/hurl/tests_ok/help.out.pattern index 2beaa4842..d6f102886 100644 --- a/integration/hurl/tests_ok/help.out.pattern +++ b/integration/hurl/tests_ok/help.out.pattern @@ -67,6 +67,8 @@ Options: IPv4 --json Output each Hurl file result to JSON + --max-filesize + Specify the maximum size (in bytes) of a file to download --max-redirs Maximum number of redirects allowed, -1 for unlimited redirects [default: 50] -m, --max-time diff --git a/packages/hurl/README.md b/packages/hurl/README.md index e8f9eb9ca..4b9d5d892 100644 --- a/packages/hurl/README.md +++ b/packages/hurl/README.md @@ -968,6 +968,7 @@ will follow a redirection only for the second entry. | --key <KEY> | Private key file name.
| | -L, --location | Follow redirect. To limit the amount of redirects to follow use the [`--max-redirs`](#max-redirs) option
| | --location-trusted | Like [`-L, --location`](#location), but allows sending the name + password to all hosts that the site may redirect to.
This may or may not introduce a security breach if the site redirects you to a site to which you send your authentication info (which is plaintext in the case of HTTP Basic authentication).
| +| --max-filesize <BYTES> | Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer does not start.
| | --max-redirs <NUM> | Set maximum number of redirection-followings allowed

By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.
| | -m, --max-time <SECONDS> | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.

See also [`--connect-timeout`](#connect-timeout).

This is a cli-only option.
| | -n, --netrc | Scan the .netrc file in the user's home directory for the username and password.

See also [`--netrc-file`](#netrc-file) and [`--netrc-optional`](#netrc-optional).
| diff --git a/packages/hurl/src/cli/options/commands.rs b/packages/hurl/src/cli/options/commands.rs index b2cc0700d..fcc6c0df8 100644 --- a/packages/hurl/src/cli/options/commands.rs +++ b/packages/hurl/src/cli/options/commands.rs @@ -282,6 +282,15 @@ pub fn json() -> clap::Arg { .action(clap::ArgAction::SetTrue) } +pub fn max_filesize() -> clap::Arg { + clap::Arg::new("max_filesize") + .long("max-filesize") + .value_name("BYTES") + .value_parser(clap::value_parser!(u64)) + .help("Specify the maximum size (in bytes) of a file to download") + .num_args(1) +} + pub fn max_redirects() -> clap::Arg { clap::Arg::new("max_redirects") .long("max-redirs") diff --git a/packages/hurl/src/cli/options/matches.rs b/packages/hurl/src/cli/options/matches.rs index e2855cce9..e45a2d5ef 100644 --- a/packages/hurl/src/cli/options/matches.rs +++ b/packages/hurl/src/cli/options/matches.rs @@ -423,6 +423,10 @@ pub fn very_verbose(arg_matches: &ArgMatches) -> bool { has_flag(arg_matches, "very_verbose") } +pub fn max_filesize(arg_matches: &ArgMatches) -> Option { + get::(arg_matches, "max_filesize") +} + /// Returns a list of path names from the command line options `matches`. fn glob_files(matches: &ArgMatches) -> Result, CliOptionsError> { let mut all_files = vec![]; diff --git a/packages/hurl/src/cli/options/mod.rs b/packages/hurl/src/cli/options/mod.rs index 1e46a7b19..f966c6de4 100644 --- a/packages/hurl/src/cli/options/mod.rs +++ b/packages/hurl/src/cli/options/mod.rs @@ -67,6 +67,7 @@ pub struct CliOptions { pub ip_resolve: Option, pub jobs: Option, pub junit_file: Option, + pub max_filesize: Option, pub max_redirect: Option, pub netrc: bool, pub netrc_file: Option, @@ -191,6 +192,7 @@ pub fn parse() -> Result { .arg(commands::ipv6()) .arg(commands::jobs()) .arg(commands::json()) + .arg(commands::max_filesize()) .arg(commands::max_redirects()) .arg(commands::max_time()) .arg(commands::netrc()) @@ -264,6 +266,7 @@ fn parse_matches(arg_matches: &ArgMatches) -> Result Result Result Result ip.into(), None => http::IpResolve::default(), }; + let max_filesize = self.max_filesize; let max_redirect = self.max_redirect; let netrc = self.netrc; let netrc_file = self.netrc_file.clone(); @@ -466,6 +471,7 @@ impl CliOptions { .ignore_asserts(ignore_asserts) .insecure(insecure) .ip_resolve(ip_resolve) + .max_filesize(max_filesize) .max_redirect(max_redirect) .netrc(netrc) .netrc_file(netrc_file) diff --git a/packages/hurl/src/http/client.rs b/packages/hurl/src/http/client.rs index 93887083c..4c685f784 100644 --- a/packages/hurl/src/http/client.rs +++ b/packages/hurl/src/http/client.rs @@ -439,6 +439,9 @@ impl Client { } self.handle.timeout(options.timeout)?; self.handle.connect_timeout(options.connect_timeout)?; + if let Some(max_filesize) = options.max_filesize { + self.handle.max_filesize(max_filesize)?; + } self.set_ssl_options(options.ssl_no_revoke)?; diff --git a/packages/hurl/src/http/options.rs b/packages/hurl/src/http/options.rs index f57567a49..acb6b9f65 100644 --- a/packages/hurl/src/http/options.rs +++ b/packages/hurl/src/http/options.rs @@ -37,6 +37,7 @@ pub struct ClientOptions { pub http_version: RequestedHttpVersion, pub insecure: bool, pub ip_resolve: IpResolve, + pub max_filesize: Option, pub max_redirect: Option, pub netrc: bool, pub netrc_file: Option, @@ -77,6 +78,7 @@ impl Default for ClientOptions { http_version: RequestedHttpVersion::default(), insecure: false, ip_resolve: IpResolve::default(), + max_filesize: None, max_redirect: Some(50), netrc: false, netrc_file: None, @@ -152,6 +154,10 @@ impl ClientOptions { } else if self.follow_location { arguments.push("--location".to_string()); } + if let Some(max_filesize) = self.max_filesize { + arguments.push("--max-filesize".to_string()); + arguments.push(max_filesize.to_string()); + } if self.max_redirect != ClientOptions::default().max_redirect { let max_redirect = match self.max_redirect { None => -1, @@ -224,6 +230,7 @@ mod tests { http_version: RequestedHttpVersion::Http10, insecure: true, ip_resolve: IpResolve::IpV6, + max_filesize: None, max_redirect: Some(10), netrc: false, netrc_file: Some("/var/run/netrc".to_string()), @@ -233,7 +240,7 @@ mod tests { no_proxy: None, resolves: vec![ "foo.com:80:192.168.0.1".to_string(), - "bar.com:443:127.0.0.1".to_string() + "bar.com:443:127.0.0.1".to_string(), ], retry: Retry::None, ssl_no_revoke: false, diff --git a/packages/hurl/src/runner/entry.rs b/packages/hurl/src/runner/entry.rs index 97e77dfd8..2f656e72e 100644 --- a/packages/hurl/src/runner/entry.rs +++ b/packages/hurl/src/runner/entry.rs @@ -211,6 +211,7 @@ impl ClientOptions { follow_location_trusted: runner_options.follow_location_trusted, http_version: runner_options.http_version, ip_resolve: runner_options.ip_resolve, + max_filesize: runner_options.max_filesize, max_redirect: runner_options.max_redirect, netrc: runner_options.netrc, netrc_file: runner_options.netrc_file.clone(), diff --git a/packages/hurl/src/runner/runner_options.rs b/packages/hurl/src/runner/runner_options.rs index 25ef50fbc..2ff78cdc8 100644 --- a/packages/hurl/src/runner/runner_options.rs +++ b/packages/hurl/src/runner/runner_options.rs @@ -42,6 +42,7 @@ pub struct RunnerOptionsBuilder { ignore_asserts: bool, insecure: bool, ip_resolve: IpResolve, + max_filesize: Option, max_redirect: Option, netrc: bool, netrc_file: Option, @@ -85,6 +86,7 @@ impl Default for RunnerOptionsBuilder { ignore_asserts: false, insecure: false, ip_resolve: IpResolve::default(), + max_filesize: None, max_redirect: Some(50), netrc: false, netrc_file: None, @@ -375,6 +377,12 @@ impl RunnerOptionsBuilder { self } + /// Set the file size limit + pub fn max_filesize(&mut self, max_filesize: Option) -> &mut Self { + self.max_filesize = max_filesize; + self + } + /// Create an instance of [`RunnerOptions`]. pub fn build(&self) -> RunnerOptions { RunnerOptions { @@ -396,6 +404,7 @@ impl RunnerOptionsBuilder { ignore_asserts: self.ignore_asserts, insecure: self.insecure, ip_resolve: self.ip_resolve, + max_filesize: self.max_filesize, max_redirect: self.max_redirect, netrc: self.netrc, netrc_file: self.netrc_file.clone(), @@ -440,6 +449,7 @@ pub struct RunnerOptions { pub(crate) ignore_asserts: bool, pub(crate) ip_resolve: IpResolve, pub(crate) insecure: bool, + pub(crate) max_filesize: Option, pub(crate) max_redirect: Option, pub(crate) netrc: bool, pub(crate) netrc_file: Option,