Use HTTP instead of HTTP/* for any HTTP version match

This commit is contained in:
jcamiel 2022-11-10 22:28:57 +01:00
parent fef446a4e0
commit 4e41799623
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
25 changed files with 154 additions and 118 deletions

View File

@ -1,7 +1,7 @@
error: Parsing version error: Parsing version
--> tests_error_parser/version.hurl:2:6 --> tests_error_parser/version.hurl:2:1
| |
2 | HTTP/11 200 2 | HTTP/11 200
| ^ HTTP version must be 1.0, 1.1, 2 or * | ^ HTTP version must be HTTP, HTTP/1.0, HTTP/1.1 or HTTP/2
| |

View File

@ -1,7 +1,7 @@
error: Assert HTTP version error: Assert HTTP version
--> tests_failed/assert_http_version.hurl:2:6 --> tests_failed/assert_http_version.hurl:2:1
| |
2 | HTTP/2 200 2 | HTTP/2 200
| ^ actual value is <1.0> | ^^^^^^ actual value is <HTTP/1.0>
| |

View File

@ -34,6 +34,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/option_retry.hurl:6:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/option_retry.hurl:6:8 * --> tests_failed/option_retry.hurl:6:8
@ -72,6 +73,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/option_retry.hurl:6:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/option_retry.hurl:6:8 * --> tests_failed/option_retry.hurl:6:8
@ -110,6 +112,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/option_retry.hurl:6:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* *
* Retry max count reached, no more retry * Retry max count reached, no more retry

View File

@ -1,3 +1,4 @@
warning: tests_failed/query_match_none.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
error: Assert failure error: Assert failure
--> tests_failed/query_match_none.hurl:4:0 --> tests_failed/query_match_none.hurl:4:0
| |

View File

@ -29,6 +29,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/retry.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/retry.hurl:2:8 * --> tests_failed/retry.hurl:2:8
@ -62,6 +63,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/retry.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/retry.hurl:2:8 * --> tests_failed/retry.hurl:2:8
@ -95,6 +97,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/retry.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/retry.hurl:2:8 * --> tests_failed/retry.hurl:2:8
@ -128,6 +131,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/retry.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/retry.hurl:2:8 * --> tests_failed/retry.hurl:2:8
@ -161,6 +165,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/retry.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert status code * Assert status code
* --> tests_failed/retry.hurl:2:8 * --> tests_failed/retry.hurl:2:8
@ -194,6 +199,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_failed/retry.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* *
* Retry max count reached, no more retry * Retry max count reached, no more retry

View File

@ -1,16 +1,16 @@
<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/hello</span></span> <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/hello</span></span>
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span> </span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="raw"><span class="line">```Hello World!```</span></span> <span class="raw"><span class="line">```Hello World!```</span></span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span> </span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/hello</span></span> <span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/hello</span></span>
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span> </span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line">file, <span class="filename">data.txt</span>;</span> <span class="line">file, <span class="filename">data.txt</span>;</span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span> </span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/hello</span></span> <span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/hello</span></span>
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span> </span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line">hex, <span class="hex">48656c6c6f20576f726c6421</span>;</span> <span class="line">hex, <span class="hex">48656c6c6f20576f726c6421</span>;</span>
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span> </span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/hello</span></span> <span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/hello</span></span>
</span><span class="response"><span class="line"><span class="version">HTTP/1.0</span> <span class="number">200</span></span> </span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
<span class="line">base64, <span class="base64">SGVsbG8gV29ybGQh</span>;</span> <span class="line">base64, <span class="base64">SGVsbG8gV29ybGQh</span>;</span>
</span></span></code></pre> </span></span></code></pre>

View File

@ -1,15 +1,15 @@
GET http://localhost:8000/hello GET http://localhost:8000/hello
HTTP/1.0 200 HTTP 200
```Hello World!``` ```Hello World!```
GET http://localhost:8000/hello GET http://localhost:8000/hello
HTTP/1.0 200 HTTP 200
file, data.txt; file, data.txt;
GET http://localhost:8000/hello GET http://localhost:8000/hello
HTTP/1.0 200 HTTP 200
hex, 48656c6c6f20576f726c6421; hex, 48656c6c6f20576f726c6421;
GET http://localhost:8000/hello GET http://localhost:8000/hello
HTTP/1.0 200 HTTP 200
base64, SGVsbG8gV29ybGQh; base64, SGVsbG8gV29ybGQh;

View File

@ -1 +1 @@
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"raw-string","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"version":"HTTP/1.0","status":200,"body":{"type":"file","filename":"data.txt"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"version":"HTTP/1.0","status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"version":"HTTP/1.0","status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}}]} {"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"type":"raw-string","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"type":"file","filename":"data.txt"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}}]}

View File

@ -29,6 +29,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:4:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* Captures: * Captures:
* job_id: ~~~ * job_id: ~~~
* *
@ -60,6 +61,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:17:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/option_retry.hurl:19:0 * --> tests_ok/option_retry.hurl:19:0
@ -98,6 +100,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:17:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/option_retry.hurl:19:0 * --> tests_ok/option_retry.hurl:19:0
@ -136,6 +139,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:17:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/option_retry.hurl:19:0 * --> tests_ok/option_retry.hurl:19:0
@ -174,6 +178,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:17:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/option_retry.hurl:19:0 * --> tests_ok/option_retry.hurl:19:0
@ -212,6 +217,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:17:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 3 * Executing entry 3
@ -237,6 +243,7 @@
< Content-Length: 0 < Content-Length: 0
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:24:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 4 * Executing entry 4
@ -262,4 +269,5 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_retry.hurl:27:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *

View File

@ -25,6 +25,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/option_verbose.hurl:7:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 4 * Executing entry 4

View File

@ -29,6 +29,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:4:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* Captures: * Captures:
* job_id: ~~~ * job_id: ~~~
* *
@ -56,6 +57,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:14:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/retry.hurl:16:0 * --> tests_ok/retry.hurl:16:0
@ -90,6 +92,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:14:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/retry.hurl:16:0 * --> tests_ok/retry.hurl:16:0
@ -124,6 +127,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:14:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/retry.hurl:16:0 * --> tests_ok/retry.hurl:16:0
@ -158,6 +162,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:14:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* Assert failure * Assert failure
* --> tests_ok/retry.hurl:16:0 * --> tests_ok/retry.hurl:16:0
@ -192,6 +197,7 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:14:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 3 * Executing entry 3
@ -217,6 +223,7 @@
< Content-Length: 0 < Content-Length: 0
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:21:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 4 * Executing entry 4
@ -242,4 +249,5 @@
< Server: Flask Server < Server: Flask Server
< Date: ~~~ < Date: ~~~
< <
warning: tests_ok/retry.hurl:24:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *

View File

@ -75,6 +75,7 @@
< <
* Response body: * Response body:
* Redirected. * Redirected.
warning: tests_ok/very_verbose.hurl:2:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 2 * Executing entry 2
@ -110,6 +111,7 @@
< <
* Response body: * Response body:
* café * café
warning: tests_ok/very_verbose.hurl:5:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 3 * Executing entry 3
@ -156,6 +158,7 @@
< <
* Response body: * Response body:
* Hello World! * Hello World!
warning: tests_ok/very_verbose.hurl:13:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 4 * Executing entry 4
@ -191,6 +194,7 @@
< <
* Response body: * Response body:
* Bytes <f198388ba26c2c53005f24643826384f15ba905b8ca070a470b61885c6639f8bbfe63fcee5fb498a630249e499e4eddcc9ca793406c14d02c97107e09c7af57a...> * Bytes <f198388ba26c2c53005f24643826384f15ba905b8ca070a470b61885c6639f8bbfe63fcee5fb498a630249e499e4eddcc9ca793406c14d02c97107e09c7af57a...>
warning: tests_ok/very_verbose.hurl:16:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 5 * Executing entry 5
@ -233,6 +237,7 @@
< <
* Response body: * Response body:
* *
warning: tests_ok/very_verbose.hurl:21:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *
* ------------------------------------------------------------------------------ * ------------------------------------------------------------------------------
* Executing entry 6 * Executing entry 6
@ -270,4 +275,5 @@
< <
* Response body: * Response body:
* Done * Done
warning: tests_ok/very_verbose.hurl:25:1 'HTTP/*' keyword is deprecated, please use 'HTTP' instead
* *

View File

@ -40,9 +40,9 @@ pub enum Version {
impl fmt::Display for Version { impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let value = match self { let value = match self {
Version::Http10 => "1.0", Version::Http10 => "HTTP/1.0",
Version::Http11 => "1.1", Version::Http11 => "HTTP/1.1",
Version::Http2 => "2", Version::Http2 => "HTTP/2",
}; };
write!(f, "{}", value) write!(f, "{}", value)
} }

View File

@ -514,7 +514,7 @@ fn get_summary(duration: u128, hurl_results: &[HurlResult]) -> String {
/// Returns status, version and HTTP headers from an HTTP `response`. /// Returns status, version and HTTP headers from an HTTP `response`.
fn get_status_line_headers(response: &Response, color: bool) -> String { fn get_status_line_headers(response: &Response, color: bool) -> String {
let mut str = String::new(); let mut str = String::new();
let status_line = format!("HTTP/{} {}\n", response.version, response.status); let status_line = format!("{} {}\n", response.version, response.status);
let status_line = if color { let status_line = if color {
format!("{}", status_line.green().bold()) format!("{}", status_line.green().bold())
} else { } else {

View File

@ -29,6 +29,7 @@ use super::query::eval_query;
use super::value::Value; use super::value::Value;
impl AssertResult { impl AssertResult {
/// Evaluates an assert and returns `None` if assert is succeeded or an `Error` if failed.
pub fn error(&self) -> Option<Error> { pub fn error(&self) -> Option<Error> {
match self { match self {
AssertResult::Version { AssertResult::Version {
@ -36,7 +37,10 @@ impl AssertResult {
expected, expected,
source_info, source_info,
} => { } => {
if expected.as_str() == "*" || actual == expected { if expected.as_str() == "HTTP"
|| expected.as_str() == "HTTP/*"
|| actual == expected
{
None None
} else { } else {
Some(Error { Some(Error {

View File

@ -21,6 +21,7 @@ use std::time::Duration;
use crate::cli::Logger; use crate::cli::Logger;
use crate::http; use crate::http;
use crate::http::ClientOptions; use crate::http::ClientOptions;
use hurl_core::ast::VersionValue::VersionAnyLegacy;
use hurl_core::ast::*; use hurl_core::ast::*;
use super::core::*; use super::core::*;
@ -61,8 +62,7 @@ pub fn run(
}; };
let client_options = http::ClientOptions::from(runner_options); let client_options = http::ClientOptions::from(runner_options);
// Experimental features // Experimental features with cookie storage
// with cookie storage
use std::str::FromStr; use std::str::FromStr;
if let Some(s) = cookie_storage_set(&entry.request) { if let Some(s) = cookie_storage_set(&entry.request) {
if let Ok(cookie) = http::Cookie::from_str(s.as_str()) { if let Ok(cookie) = http::Cookie::from_str(s.as_str()) {
@ -114,6 +114,23 @@ pub fn run(
} }
}; };
// We display some warning if HTTP/* is used instead of HTTP.
if let Some(response) = &entry.response {
let version = &response.version;
let source_info = &version.source_info;
let line = &source_info.start.line;
let column = &source_info.start.column;
if version.value == VersionAnyLegacy {
logger.warning(
format!(
"{}:{}:{} 'HTTP/*' keyword is deprecated, please use 'HTTP' instead",
logger.filename, line, column
)
.as_str(),
);
}
}
// We runs capture and asserts on the last HTTP request/response chains. // We runs capture and asserts on the last HTTP request/response chains.
let (_, http_response) = calls.last().unwrap(); let (_, http_response) = calls.last().unwrap();
let calls: Vec<Call> = calls let calls: Vec<Call> = calls

View File

@ -30,12 +30,7 @@ use super::template::eval_template;
use super::value::Value; use super::value::Value;
use crate::runner::multipart::eval_multipart_param; use crate::runner::multipart::eval_multipart_param;
/// Transforms an AST request to a spec request given a set of variables. /// Transforms an AST `request` to a spec request given a set of `variables`.
///
/// # Arguments
/// * `request` - An AST request
/// * `variables` - A set of variables for templates/expressions.
/// * `context_dir` - The context directory
pub fn eval_request( pub fn eval_request(
request: &Request, request: &Request,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,

View File

@ -29,14 +29,7 @@ use super::json::eval_json_value;
use super::template::eval_template; use super::template::eval_template;
use super::value::Value; use super::value::Value;
/// Returns a list of response assert results. /// Returns a list of assert results, given a set of `variables`, an actual `http_response` and a spec `response`.
///
/// # Arguments
///
/// * `response` - The spec HTTP response
/// * `variables` - A map of input variables
/// * `http_response` - The actual HTTP response
/// * `context_dir` - The context directory for files
pub fn eval_asserts( pub fn eval_asserts(
response: &Response, response: &Response,
variables: &HashMap<String, Value>, variables: &HashMap<String, Value>,
@ -45,23 +38,23 @@ pub fn eval_asserts(
) -> Vec<AssertResult> { ) -> Vec<AssertResult> {
let mut asserts = vec![]; let mut asserts = vec![];
let version = response.clone().version; let version = &response.version;
asserts.push(AssertResult::Version { asserts.push(AssertResult::Version {
actual: http_response.version.to_string(), actual: http_response.version.to_string(),
expected: version.value.as_str().to_string(), expected: version.value.to_string(),
source_info: version.source_info, source_info: version.source_info.clone(),
}); });
let status = response.clone().status; let status = &response.status;
if let StatusValue::Specific(v) = status.value { if let StatusValue::Specific(v) = status.value {
asserts.push(AssertResult::Status { asserts.push(AssertResult::Status {
actual: http_response.status as u64, actual: http_response.status as u64,
expected: v as u64, expected: v as u64,
source_info: status.source_info, source_info: status.source_info.clone(),
}); });
} }
for header in response.clone().headers { for header in response.headers.iter() {
match eval_template(&header.value, variables) { match eval_template(&header.value, variables) {
Err(e) => { Err(e) => {
asserts.push(AssertResult::Header { asserts.push(AssertResult::Header {
@ -322,7 +315,7 @@ mod tests {
line_terminators: vec![], line_terminators: vec![],
version: Version { version: Version {
value: VersionValue::Version1, value: VersionValue::Version1,
source_info: SourceInfo::new(2, 6, 2, 9), source_info: SourceInfo::new(2, 1, 2, 9),
}, },
space0: whitespace.clone(), space0: whitespace.clone(),
status: Status { status: Status {
@ -366,9 +359,9 @@ mod tests {
), ),
vec![ vec![
AssertResult::Version { AssertResult::Version {
actual: String::from("1.0"), actual: String::from("HTTP/1.0"),
expected: String::from("1.0"), expected: String::from("HTTP/1.0"),
source_info: SourceInfo::new(2, 6, 2, 9), source_info: SourceInfo::new(2, 1, 2, 9),
}, },
AssertResult::Status { AssertResult::Status {
actual: 200, actual: 200,

View File

@ -152,17 +152,7 @@ pub enum VersionValue {
Version11, Version11,
Version2, Version2,
VersionAny, VersionAny,
} VersionAnyLegacy,
impl VersionValue {
pub fn as_str<'a>(&self) -> &'a str {
match self {
VersionValue::Version1 => "1.0",
VersionValue::Version11 => "1.1",
VersionValue::Version2 => "2",
VersionValue::VersionAny => "*",
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -44,10 +44,11 @@ impl fmt::Display for Version {
impl fmt::Display for VersionValue { impl fmt::Display for VersionValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self { let s = match self {
VersionValue::Version1 => "1.0", VersionValue::Version1 => "HTTP/1.0",
VersionValue::Version11 => "1.1", VersionValue::Version11 => "HTTP/1.1",
VersionValue::Version2 => "2", VersionValue::Version2 => "HTTP/2",
VersionValue::VersionAny => "*", VersionValue::VersionAny => "HTTP",
VersionValue::VersionAnyLegacy => "HTTP/*",
}; };
write!(f, "{}", s) write!(f, "{}", s)
} }

View File

@ -70,7 +70,7 @@ impl Error for parser::Error {
name.as_str(), name.as_str(),
"Available HTTP Methods are GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE or PATCH", "Available HTTP Methods are GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE or PATCH",
)), )),
ParseError::Version { .. } => "HTTP version must be 1.0, 1.1, 2 or *".to_string(), ParseError::Version { .. } => "HTTP version must be HTTP, HTTP/1.0, HTTP/1.1 or HTTP/2".to_string(),
ParseError::Status { .. } => "HTTP status code is not valid".to_string(), ParseError::Status { .. } => "HTTP status code is not valid".to_string(),
ParseError::Filename { .. } => "expecting a filename".to_string(), ParseError::Filename { .. } => "expecting a filename".to_string(),
ParseError::Expecting { value } => format!("expecting '{}'", value), ParseError::Expecting { value } => format!("expecting '{}'", value),

View File

@ -136,10 +136,7 @@ impl Htmlable for Method {
impl Htmlable for Version { impl Htmlable for Version {
fn to_html(&self) -> String { fn to_html(&self) -> String {
format!( format!("<span class=\"version\">{}</span>", self.value)
"<span class=\"version\">HTTP/{}</span>",
self.value.as_str()
)
} }
} }

View File

@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
* *
*/ */
use crate::ast::VersionValue::VersionAny;
use crate::ast::*; use crate::ast::*;
use super::bytes::*; use super::bytes::*;
@ -160,32 +161,52 @@ fn method(reader: &mut Reader) -> ParseResult<'static, Method> {
} }
fn version(reader: &mut Reader) -> ParseResult<'static, Version> { fn version(reader: &mut Reader) -> ParseResult<'static, Version> {
try_literal("HTTP/", reader)?;
let available_version = vec![
("1.0", VersionValue::Version1),
("1.1", VersionValue::Version11),
("2", VersionValue::Version2),
("*", VersionValue::VersionAny),
];
let start = reader.state.clone(); let start = reader.state.clone();
for (s, value) in available_version { try_literal("HTTP", reader)?;
if try_literal(s, reader).is_ok() {
return Ok(Version { let next_c = reader.peek();
value, match next_c {
source_info: SourceInfo::new( Some('/') => {
start.pos.line, let available_version = vec![
start.pos.column, ("/1.0", VersionValue::Version1),
reader.state.pos.line, ("/1.1", VersionValue::Version11),
reader.state.pos.column, ("/2", VersionValue::Version2),
), ("/*", VersionValue::VersionAnyLegacy),
}); ];
for (s, value) in available_version.iter() {
if try_literal(s, reader).is_ok() {
return Ok(Version {
value: value.clone(),
source_info: SourceInfo::new(
start.pos.line,
start.pos.column,
reader.state.pos.line,
reader.state.pos.column,
),
});
}
}
Err(Error {
pos: start.pos,
recoverable: false,
inner: ParseError::Version {},
})
} }
Some(' ') => Ok(Version {
value: VersionAny,
source_info: SourceInfo::new(
start.pos.line,
start.pos.column,
reader.state.pos.line,
reader.state.pos.column,
),
}),
_ => Err(Error {
pos: start.pos,
recoverable: false,
inner: ParseError::Version {},
}),
} }
Err(Error {
pos: start.pos,
recoverable: false,
inner: ParseError::Version {},
})
} }
fn status(reader: &mut Reader) -> ParseResult<'static, Status> { fn status(reader: &mut Reader) -> ParseResult<'static, Status> {
@ -514,7 +535,7 @@ mod tests {
let mut reader = Reader::init("HTTP/1. 200"); let mut reader = Reader::init("HTTP/1. 200");
let error = version(&mut reader).err().unwrap(); let error = version(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 6 }); assert_eq!(error.pos, Pos { line: 1, column: 1 });
} }
#[test] #[test]
@ -530,7 +551,6 @@ mod tests {
let mut reader = Reader::init("xxx"); let mut reader = Reader::init("xxx");
let result = status(&mut reader); let result = status(&mut reader);
assert!(result.is_err()); assert!(result.is_err());
// assert!(result.err().unwrap().pos, Pos { line: 1, column: 1 });
} }
#[test] #[test]

View File

@ -39,7 +39,7 @@ impl ToJson for HurlFile {
impl ToJson for Entry { impl ToJson for Entry {
fn to_json(&self) -> JValue { fn to_json(&self) -> JValue {
let mut attributes = vec![("request".to_string(), self.request.to_json())]; let mut attributes = vec![("request".to_string(), self.request.to_json())];
if let Some(response) = self.response.clone() { if let Some(response) = &self.response {
attributes.push(("response".to_string(), response.to_json())); attributes.push(("response".to_string(), response.to_json()));
} }
JValue::Object(attributes) JValue::Object(attributes)
@ -55,40 +55,33 @@ impl ToJson for Request {
), ),
("url".to_string(), JValue::String(self.url.to_string())), ("url".to_string(), JValue::String(self.url.to_string())),
]; ];
add_headers(&mut attributes, self.headers.clone()); add_headers(&mut attributes, &self.headers);
if !self.clone().querystring_params().is_empty() { if !self.querystring_params().is_empty() {
let params = self let params = self
.clone()
.querystring_params() .querystring_params()
.iter() .iter()
.map(|p| p.to_json()) .map(|p| p.to_json())
.collect(); .collect();
attributes.push(("query_string_params".to_string(), JValue::List(params))); attributes.push(("query_string_params".to_string(), JValue::List(params)));
} }
if !self.clone().form_params().is_empty() { if !self.form_params().is_empty() {
let params = self let params = self.form_params().iter().map(|p| p.to_json()).collect();
.clone()
.form_params()
.iter()
.map(|p| p.to_json())
.collect();
attributes.push(("form_params".to_string(), JValue::List(params))); attributes.push(("form_params".to_string(), JValue::List(params)));
} }
if !self.clone().multipart_form_data().is_empty() { if !self.multipart_form_data().is_empty() {
let params = self let params = self
.clone()
.multipart_form_data() .multipart_form_data()
.iter() .iter()
.map(|p| p.to_json()) .map(|p| p.to_json())
.collect(); .collect();
attributes.push(("multipart_form_data".to_string(), JValue::List(params))); attributes.push(("multipart_form_data".to_string(), JValue::List(params)));
} }
if !self.clone().cookies().is_empty() { if !self.cookies().is_empty() {
let cookies = self.clone().cookies().iter().map(|c| c.to_json()).collect(); let cookies = self.cookies().iter().map(|c| c.to_json()).collect();
attributes.push(("cookies".to_string(), JValue::List(cookies))); attributes.push(("cookies".to_string(), JValue::List(cookies)));
} }
if let Some(body) = self.body.clone() { if let Some(body) = &self.body {
attributes.push(("body".to_string(), body.to_json())); attributes.push(("body".to_string(), body.to_json()));
} }
JValue::Object(attributes) JValue::Object(attributes)
@ -99,13 +92,13 @@ impl ToJson for Response {
/// Transforms this response to a JSON object. /// Transforms this response to a JSON object.
fn to_json(&self) -> JValue { fn to_json(&self) -> JValue {
let mut attributes = vec![]; let mut attributes = vec![];
if let Some(v) = get_json_version(self.version.value.clone()) { if let Some(v) = get_json_version(&self.version.value) {
attributes.push(("version".to_string(), JValue::String(v))) attributes.push(("version".to_string(), JValue::String(v)))
} }
if let StatusValue::Specific(n) = self.status.value { if let StatusValue::Specific(n) = self.status.value {
attributes.push(("status".to_string(), JValue::Number(n.to_string()))); attributes.push(("status".to_string(), JValue::Number(n.to_string())));
} }
add_headers(&mut attributes, self.headers.clone()); add_headers(&mut attributes, &self.headers);
if !self.captures().is_empty() { if !self.captures().is_empty() {
let captures = self.captures().iter().map(|c| c.to_json()).collect(); let captures = self.captures().iter().map(|c| c.to_json()).collect();
attributes.push(("captures".to_string(), JValue::List(captures))); attributes.push(("captures".to_string(), JValue::List(captures)));
@ -121,7 +114,7 @@ impl ToJson for Response {
} }
} }
fn add_headers(attributes: &mut Vec<(String, JValue)>, headers: Vec<Header>) { fn add_headers(attributes: &mut Vec<(String, JValue)>, headers: &Vec<Header>) {
if !headers.is_empty() { if !headers.is_empty() {
let headers = JValue::List(headers.iter().map(|h| h.to_json()).collect()); let headers = JValue::List(headers.iter().map(|h| h.to_json()).collect());
attributes.push(("headers".to_string(), headers)) attributes.push(("headers".to_string(), headers))
@ -191,12 +184,13 @@ impl ToJson for File {
} }
} }
fn get_json_version(version_value: VersionValue) -> Option<String> { fn get_json_version(version_value: &VersionValue) -> Option<String> {
match version_value { match version_value {
VersionValue::Version1 => Some("HTTP/1.0".to_string()), VersionValue::Version1 => Some("HTTP/1.0".to_string()),
VersionValue::Version11 => Some("HTTP/1.1".to_string()), VersionValue::Version11 => Some("HTTP/1.1".to_string()),
VersionValue::Version2 => Some("HTTP/2".to_string()), VersionValue::Version2 => Some("HTTP/2".to_string()),
VersionValue::VersionAny => None, VersionValue::VersionAny => None,
VersionValue::VersionAnyLegacy => None,
} }
} }

View File

@ -134,15 +134,7 @@ impl Tokenizable for Status {
impl Tokenizable for Version { impl Tokenizable for Version {
fn tokenize(&self) -> Vec<Token> { fn tokenize(&self) -> Vec<Token> {
vec![Token::Version(format!( vec![Token::Version(self.value.to_string())]
"HTTP/{}",
match self.value {
VersionValue::Version1 => String::from("1.0"),
VersionValue::Version11 => String::from("1.1"),
VersionValue::Version2 => String::from("2"),
VersionValue::VersionAny => String::from("*"),
}
))]
} }
} }