Add --http1.0 option

This commit is contained in:
jcamiel 2023-08-09 10:01:54 +02:00 committed by hurl-bot
parent f444ebdb11
commit 2438905850
No known key found for this signature in database
GPG Key ID: 1283A2B4A0DCAF8D
16 changed files with 110 additions and 17 deletions

View File

@ -0,0 +1 @@
curl --http1.0 'http://localhost:8000/http_version/10'

View File

@ -0,0 +1,3 @@
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/http_version/10</span></span>
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
</span></span></code></pre>

View File

@ -0,0 +1,2 @@
GET http://localhost:8000/http_version/10
HTTP 200

View File

@ -0,0 +1 @@
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/http_version/10"},"response":{"status":200}}]}

View File

@ -0,0 +1 @@
HTTP/1.0

View File

@ -0,0 +1,3 @@
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
hurl --http1.0 tests_ok/http_version.hurl

View File

@ -0,0 +1,9 @@
from app import app
from flask import request
@app.route("/http_version/10")
def http_10():
version = request.environ["SERVER_PROTOCOL"]
assert version == "HTTP/1.0"
return "HTTP/1.0"

View File

@ -0,0 +1,3 @@
#!/bin/bash
set -Eeuo pipefail
hurl --http1.0 tests_ok/http_version.hurl

View File

@ -161,6 +161,14 @@ pub fn glob() -> clap::Arg {
.number_of_values(1)
}
pub fn http10() -> clap::Arg {
clap::Arg::new("http10")
.short('0')
.long("http1.0")
.help("Tells Hurl to use HTTP version 1.0 instead of using its internally preferred HTTP version")
.action(ArgAction::SetTrue)
}
pub fn include() -> clap::Arg {
clap::Arg::new("include")
.short('i')

View File

@ -17,7 +17,7 @@
*/
use super::variables::{parse as parse_variable, parse_value};
use super::OptionsError;
use crate::cli::options::ErrorFormat;
use crate::cli::options::{ErrorFormat, HttpVersion};
use crate::cli::OutputType;
use clap::ArgMatches;
use hurl::runner::Value;
@ -169,6 +169,14 @@ pub fn html_dir(arg_matches: &ArgMatches) -> Result<Option<PathBuf>, OptionsErro
}
}
pub fn http_version(arg_matches: &ArgMatches) -> Option<HttpVersion> {
if has_flag(arg_matches, "http10") {
Some(HttpVersion::V10)
} else {
None
}
}
pub fn ignore_asserts(arg_matches: &ArgMatches) -> bool {
has_flag(arg_matches, "ignore_asserts")
}

View File

@ -52,6 +52,7 @@ pub struct Options {
pub file_root: Option<String>,
pub follow_location: bool,
pub html_dir: Option<PathBuf>,
pub http_version: Option<HttpVersion>,
pub ignore_asserts: bool,
pub include: bool,
pub input_files: Vec<String>,
@ -102,6 +103,19 @@ pub enum ErrorFormat {
Long,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum HttpVersion {
V10,
}
impl From<HttpVersion> for http::HttpVersion {
fn from(value: HttpVersion) -> Self {
match value {
HttpVersion::V10 => http::HttpVersion::Http10,
}
}
}
impl From<ErrorFormat> for hurl::util::logger::ErrorFormat {
fn from(value: ErrorFormat) -> Self {
match value {
@ -144,6 +158,7 @@ pub fn parse() -> Result<Options, OptionsError> {
.arg(commands::file_root())
.arg(commands::follow_location())
.arg(commands::glob())
.arg(commands::http10())
.arg(commands::ignore_asserts())
.arg(commands::include())
.arg(commands::input_files())
@ -209,6 +224,7 @@ fn parse_matches(arg_matches: &ArgMatches) -> Result<Options, OptionsError> {
let file_root = matches::file_root(arg_matches);
let follow_location = matches::follow_location(arg_matches);
let html_dir = matches::html_dir(arg_matches)?;
let http_version = matches::http_version(arg_matches);
let ignore_asserts = matches::ignore_asserts(arg_matches);
let include = matches::include(arg_matches);
let input_files = matches::input_files(arg_matches)?;
@ -252,6 +268,7 @@ fn parse_matches(arg_matches: &ArgMatches) -> Result<Options, OptionsError> {
file_root,
follow_location,
html_dir,
http_version,
ignore_asserts,
include,
input_files,
@ -297,6 +314,7 @@ impl Options {
let connects_to = self.connects_to.clone();
let follow_location = self.follow_location;
let insecure = self.insecure;
let http_version = self.http_version.map(|v| v.into());
let max_redirect = self.max_redirect;
let path_as_is = self.path_as_is;
let proxy = self.proxy.clone();
@ -351,6 +369,7 @@ impl Options {
.context_dir(&context_dir)
.cookie_input_file(cookie_input_file)
.follow_location(follow_location)
.http_version(http_version)
.ignore_asserts(ignore_asserts)
.insecure(insecure)
.max_redirect(max_redirect)

View File

@ -160,6 +160,9 @@ impl Client {
}
self.handle.timeout(options.timeout)?;
self.handle.connect_timeout(options.connect_timeout)?;
if let Some(version) = options.http_version {
self.handle.http_version(version.into())?;
}
self.set_ssl_options(options.ssl_no_revoke)?;
@ -783,6 +786,17 @@ fn to_list(items: &[String]) -> List {
list
}
impl From<HttpVersion> for easy::HttpVersion {
fn from(value: HttpVersion) -> Self {
match value {
HttpVersion::Http10 => easy::HttpVersion::V10,
HttpVersion::Http11 => easy::HttpVersion::V11,
HttpVersion::Http2 => easy::HttpVersion::V2,
HttpVersion::Http3 => easy::HttpVersion::V3,
}
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -15,6 +15,7 @@
* limitations under the License.
*
*/
use crate::http::HttpVersion;
use hurl_core::ast::Retry;
use std::time::Duration;
@ -29,6 +30,7 @@ pub struct ClientOptions {
pub connects_to: Vec<String>,
pub cookie_input_file: Option<String>,
pub follow_location: bool,
pub http_version: Option<HttpVersion>,
pub insecure: bool,
pub max_redirect: Option<usize>,
pub no_proxy: Option<String>,
@ -43,6 +45,7 @@ pub struct ClientOptions {
pub verbosity: Option<Verbosity>,
}
// FIXME/ we could implement copy here
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Verbosity {
Verbose,
@ -61,6 +64,7 @@ impl Default for ClientOptions {
connects_to: vec![],
cookie_input_file: None,
follow_location: false,
http_version: None,
insecure: false,
max_redirect: Some(50),
no_proxy: None,
@ -116,6 +120,9 @@ impl ClientOptions {
if self.insecure {
arguments.push("--insecure".to_string());
}
if self.http_version == Some(HttpVersion::Http10) {
arguments.push("--http1.0".to_string());
}
if self.follow_location {
arguments.push("--location".to_string());
}
@ -168,15 +175,17 @@ mod tests {
cacert_file: None,
client_cert_file: None,
client_key_file: None,
compressed: true,
connect_timeout: Duration::from_secs(20),
connects_to: vec!["example.com:443:host-47.example.com:443".to_string()],
follow_location: true,
max_redirect: Some(10),
cookie_input_file: Some("cookie_file".to_string()),
follow_location: true,
http_version: Some(HttpVersion::Http10),
insecure: true,
max_redirect: Some(10),
path_as_is: true,
proxy: Some("localhost:3128".to_string()),
no_proxy: None,
verbosity: None,
insecure: true,
resolves: vec![
"foo.com:80:192.168.0.1".to_string(),
"bar.com:443:127.0.0.1".to_string()
@ -184,10 +193,9 @@ mod tests {
retry: Retry::None,
ssl_no_revoke: false,
timeout: Duration::from_secs(10),
connect_timeout: Duration::from_secs(20),
user: Some("user:password".to_string()),
user_agent: Some("my-useragent".to_string()),
compressed: true,
verbosity: None,
}
.curl_args(),
[
@ -199,6 +207,7 @@ mod tests {
"--cookie".to_string(),
"cookie_file".to_string(),
"--insecure".to_string(),
"--http1.0".to_string(),
"--location".to_string(),
"--max-redirs".to_string(),
"10".to_string(),

View File

@ -94,15 +94,16 @@ fn main() {
.verbosity(verbosity)
.build();
let logger = Logger::from(&logger_options);
let total = opts.input_files.len();
logger.test_running(current + 1, total);
// Run our Hurl file now
let hurl_result = execute(&content, filename, current_dir, &opts);
let hurl_result = match hurl_result {
Ok(h) => h,
Err(_) => process::exit(EXIT_ERROR_PARSING),
};
logger.test_completed(&hurl_result);
let success = hurl_result.success;

View File

@ -223,27 +223,28 @@ impl ClientOptions {
cacert_file: runner_options.cacert_file.clone(),
client_cert_file: runner_options.client_cert_file.clone(),
client_key_file: runner_options.client_key_file.clone(),
compressed: runner_options.compressed,
connect_timeout: runner_options.connect_timeout,
connects_to: runner_options.connects_to.clone(),
follow_location: runner_options.follow_location,
max_redirect: runner_options.max_redirect,
cookie_input_file: runner_options.cookie_input_file.clone(),
follow_location: runner_options.follow_location,
http_version: runner_options.http_version,
max_redirect: runner_options.max_redirect,
path_as_is: runner_options.path_as_is,
proxy: runner_options.proxy.clone(),
no_proxy: runner_options.no_proxy.clone(),
verbosity: match verbosity {
Some(Verbosity::Verbose) => Some(http::Verbosity::Verbose),
Some(Verbosity::VeryVerbose) => Some(http::Verbosity::VeryVerbose),
_ => None,
},
insecure: runner_options.insecure,
resolves: runner_options.resolves.clone(),
retry: runner_options.retry,
ssl_no_revoke: runner_options.ssl_no_revoke,
timeout: runner_options.timeout,
connect_timeout: runner_options.connect_timeout,
user: runner_options.user.clone(),
user_agent: runner_options.user_agent.clone(),
compressed: runner_options.compressed,
verbosity: match verbosity {
Some(Verbosity::Verbose) => Some(http::Verbosity::Verbose),
Some(Verbosity::VeryVerbose) => Some(http::Verbosity::VeryVerbose),
_ => None,
},
}
}
}

View File

@ -17,6 +17,7 @@
*/
use std::time::Duration;
use crate::http::HttpVersion;
use hurl_core::ast::{Entry, Retry};
use crate::util::path::ContextDir;
@ -34,6 +35,7 @@ pub struct RunnerOptionsBuilder {
continue_on_error: bool,
cookie_input_file: Option<String>,
follow_location: bool,
http_version: Option<HttpVersion>,
ignore_asserts: bool,
insecure: bool,
max_redirect: Option<usize>,
@ -67,6 +69,7 @@ impl Default for RunnerOptionsBuilder {
continue_on_error: false,
cookie_input_file: None,
follow_location: false,
http_version: None,
ignore_asserts: false,
insecure: false,
max_redirect: Some(50),
@ -190,6 +193,11 @@ impl RunnerOptionsBuilder {
self
}
pub fn http_version(&mut self, version: Option<HttpVersion>) -> &mut Self {
self.http_version = version;
self
}
/// Ignores all asserts defined in the Hurl file.
pub fn ignore_asserts(&mut self, ignore_asserts: bool) -> &mut Self {
self.ignore_asserts = ignore_asserts;
@ -312,6 +320,7 @@ impl RunnerOptionsBuilder {
continue_on_error: self.continue_on_error,
cookie_input_file: self.cookie_input_file.clone(),
follow_location: self.follow_location,
http_version: self.http_version,
ignore_asserts: self.ignore_asserts,
insecure: self.insecure,
max_redirect: self.max_redirect,
@ -346,6 +355,7 @@ pub struct RunnerOptions {
pub(crate) continue_on_error: bool,
pub(crate) cookie_input_file: Option<String>,
pub(crate) follow_location: bool,
pub(crate) http_version: Option<HttpVersion>,
pub(crate) ignore_asserts: bool,
pub(crate) insecure: bool,
pub(crate) max_redirect: Option<usize>,