Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add options section #624

Merged
merged 5 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/spec/hurl.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ request-section:
| form-params-section
| multipart-form-data-section
| cookies-section
| options-section

response-section:
captures-section
Expand Down Expand Up @@ -91,6 +92,11 @@ asserts-section:
"[Asserts]" lt
assert*

options-section:
lt*
"[Options]" lt
option*

key-value: key-string ":" value-string

multipart-form-data-param: file-param | key-value
Expand All @@ -111,6 +117,13 @@ assert:
lt*
query sp predicate lt

option:
lt*
(insecure-option | ca-certificate-option)

insecure-option: "insecure" ":" (boolean | template) lt

ca-certificate-option: "cacert" ":" filename lt

# Query

Expand Down
3 changes: 3 additions & 0 deletions integration/ssl/options.curl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
curl 'https://localhost:8001/hello' --insecure
curl 'https://localhost:8001/hello' --insecure

16 changes: 16 additions & 0 deletions integration/ssl/options.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
GET https://localhost:8001/hello
[Options]
insecure: true

HTTP/* 200
```Hello World!```


GET https://localhost:8001/hello
[Options]
# Test that options overridden is possible, last is the winner.
insecure: false
insecure: true

HTTP/* 200
```Hello World!```
7 changes: 7 additions & 0 deletions integration/tests_error_parser/options_insecure.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
error: Parsing literal
--> tests_error_parser/options_insecure.hurl:3:11
|
3 | insecure: foo
| ^ expecting 'true|false'
|

1 change: 1 addition & 0 deletions integration/tests_error_parser/options_insecure.exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2
5 changes: 5 additions & 0 deletions integration/tests_error_parser/options_insecure.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET http://localhost:8000
[Options]
insecure: foo

HTTP/* *
1 change: 1 addition & 0 deletions integration/tests_ok/options.curl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
curl 'http://localhost:8000/hello'
7 changes: 7 additions & 0 deletions integration/tests_ok/options.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<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 class="line section-header">[Options]</span>
<span class="line"></span><span class="comment"># Option insecure has no effect on HTTP endpoint</span>
<span class="line"><span class="string">insecure</span><span>:</span> <span class="boolean">false</span></span>
</span><span class="response"><span class="line"></span>
<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></span></code></pre>
7 changes: 7 additions & 0 deletions integration/tests_ok/options.hurl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GET http://localhost:8000/hello
[Options]
# Option insecure has no effect on HTTP endpoint
insecure: false

HTTP/* 200
```Hello World!```
1 change: 1 addition & 0 deletions integration/tests_ok/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"type":"raw-string","value":"Hello World!"}}}]}
1 change: 1 addition & 0 deletions integration/tests_ok/options.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World!
9 changes: 5 additions & 4 deletions packages/hurl/src/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ impl Client {
} else {
format!("{}?", url)
};
let s = self.encode_params(params);
let s = self.url_encode_params(params);
format!("{}{}", url, s)
}
}
Expand Down Expand Up @@ -417,7 +417,7 @@ impl Client {
/// Sets form params.
fn set_form(&mut self, params: &[Param]) {
if !params.is_empty() {
let s = self.encode_params(params);
let s = self.url_encode_params(params);
self.handle.post_fields_copy(s.as_str().as_bytes()).unwrap();
//self.handle.write_function(sink);
}
Expand Down Expand Up @@ -458,7 +458,7 @@ impl Client {
}

/// URL encodes parameters.
fn encode_params(&mut self, params: &[Param]) -> String {
fn url_encode_params(&mut self, params: &[Param]) -> String {
params
.iter()
.map(|p| {
Expand Down Expand Up @@ -494,6 +494,7 @@ impl Client {
}

/// Retrieves an optional location to follow
///
/// You need:
/// 1. the option follow_location set to true
/// 2. a 3xx response code
Expand Down Expand Up @@ -601,7 +602,7 @@ pub fn all_cookies(cookie_storage: &[Cookie], request_spec: &RequestSpec) -> Vec

/// Matches cookie for a given URL.
pub fn match_cookie(cookie: &Cookie, url: &str) -> bool {
// is it possible to do it with libcurl?
// FIXME: is it possible to do it with libcurl?
let url = match Url::parse(url) {
Ok(url) => url,
Err(_) => return false,
Expand Down
78 changes: 42 additions & 36 deletions packages/hurl/src/runner/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,13 @@ use super::response::{eval_asserts, eval_captures};
use super::value::Value;
use crate::runner::request::{cookie_storage_clear, cookie_storage_set};

/// Run an entry with the hurl http client
/// Return one or more EntryResults (if following redirect)
/// Runs an `entry` with `http_client` and returns one or more
/// [`EntryResult`] (if following redirect).
///
/// # Examples
///
/// ```
/// use hurl::http;
/// use hurl::runner;
///
/// // Create an http client
//// let client = http::client::Client::init(http::client::ClientOptions {
//// noproxy_hosts: vec![],
//// insecure: false,
//// redirect: http::client::Redirect::None,
//// http_proxy: None,
//// https_proxy: None,
//// all_proxy: None
//// });
/// ```
/// `variables` are used to render values at runtime, and can be updated
/// by captures.
pub fn run(
entry: &Entry,
entry_index: usize,
http_client: &mut http::Client,
variables: &mut HashMap<String, Value>,
runner_options: &RunnerOptions,
Expand All @@ -71,25 +56,21 @@ pub fn run(
}
};

logger.debug_important(
"------------------------------------------------------------------------------",
);
logger.debug_important(format!("Executing entry {}", entry_index + 1).as_str());
// We computes overridden options for this entry.
let client_options = get_entry_options(entry, client_options, logger);

//
// Experimental features
// with cookie storage
//
use std::str::FromStr;
if let Some(s) = cookie_storage_set(&entry.request) {
if let Ok(cookie) = http::Cookie::from_str(s.as_str()) {
http_client.add_cookie(&cookie, client_options);
http_client.add_cookie(&cookie, &client_options);
} else {
logger.warning(format!("Cookie string can not be parsed: '{}'", s).as_str());
}
}
if cookie_storage_clear(&entry.request) {
http_client.clear_cookie_storage(client_options);
http_client.clear_cookie_storage(&client_options);
}

logger.debug("");
Expand All @@ -102,12 +83,12 @@ pub fn run(
logger.debug("Request can be run with the following curl command:");
logger.debug(
http_client
.curl_command_line(&http_request, client_options)
.curl_command_line(&http_request, &client_options)
.as_str(),
);
logger.debug("");

let calls = match http_client.execute_with_redirect(&http_request, client_options, logger) {
let calls = match http_client.execute_with_redirect(&http_request, &client_options, logger) {
Ok(calls) => calls,
Err(http_error) => {
let runner_error = RunnerError::from(http_error);
Expand Down Expand Up @@ -208,13 +189,7 @@ pub fn run(
entry_results
}

/// Logs a HTTP request spec
///
/// # Arguments
///
/// * `request` - An HTTP request spec
/// * `logger` - A logger
///
/// Logs this HTTP `request` spec.
fn log_request_spec(request: &http::RequestSpec, logger: &Logger) {
logger.debug_important("Request:");
logger.debug(format!("{} {}", request.method, request.url).as_str());
Expand Down Expand Up @@ -251,3 +226,34 @@ fn log_request_spec(request: &http::RequestSpec, logger: &Logger) {
}
logger.debug("");
}

/// Returns a new [`ClientOptions`] based on the `entry` optional Options section
/// and a default `client_options`.
fn get_entry_options(
entry: &Entry,
client_options: &ClientOptions,
logger: &Logger,
) -> ClientOptions {
let mut client_options = client_options.clone();

let has_options = entry
.request
.sections
.iter()
.any(|s| matches!(s.value, SectionValue::Options(_)));
if has_options {
logger.debug("");
logger.debug_important("Entry options:");
}

for section in &entry.request.sections {
if let SectionValue::Options(options) = &section.value {
for option in options {
let EntryOption::Insecure(insecure_option) = option;
client_options.insecure = insecure_option.value;
logger.debug(format!("insecure: {}", client_options.insecure).as_str());
}
}
}
client_options
}
6 changes: 5 additions & 1 deletion packages/hurl/src/runner/hurl_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,13 @@ pub fn run(
break;
}

logger.debug_important(
"------------------------------------------------------------------------------",
);
logger.debug_important(format!("Executing entry {}", entry_index + 1).as_str());

let entry_results = entry::run(
&entry,
entry_index,
http_client,
&mut variables,
runner_options,
Expand Down
17 changes: 17 additions & 0 deletions packages/hurl_core/src/ast/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ impl Section {
SectionValue::Cookies(_) => "Cookies",
SectionValue::Captures(_) => "Captures",
SectionValue::MultipartFormData(_) => "MultipartFormData",
SectionValue::Options(_) => "Options",
}
}
}
Expand All @@ -221,6 +222,7 @@ pub enum SectionValue {
Cookies(Vec<Cookie>),
Captures(Vec<Capture>),
Asserts(Vec<Assert>),
Options(Vec<EntryOption>),
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -662,3 +664,18 @@ pub struct Variable {
pub name: String,
pub source_info: SourceInfo,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EntryOption {
Insecure(InsecureOption),
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InsecureOption {
pub line_terminators: Vec<LineTerminator>,
pub space0: Whitespace,
pub space1: Whitespace,
pub space2: Whitespace,
pub value: bool,
pub line_terminator0: LineTerminator,
}
30 changes: 30 additions & 0 deletions packages/hurl_core/src/format/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ impl Htmlable for SectionValue {
buffer.push_str(item.to_html().as_str())
}
}
SectionValue::Options(items) => {
for item in items {
buffer.push_str(item.to_html().as_str())
}
}
}
buffer
}
Expand All @@ -224,6 +229,31 @@ impl Htmlable for KeyValue {
}
}

impl Htmlable for EntryOption {
fn to_html(&self) -> String {
match self {
EntryOption::Insecure(option) => option.to_html(),
}
}
}

impl Htmlable for InsecureOption {
fn to_html(&self) -> String {
let mut buffer = String::from("");
add_line_terminators(&mut buffer, self.line_terminators.clone());
buffer.push_str("<span class=\"line\">");
buffer.push_str(self.space0.to_html().as_str());
buffer.push_str("<span class=\"string\">insecure</span>");
buffer.push_str(self.space1.to_html().as_str());
buffer.push_str("<span>:</span>");
buffer.push_str(self.space2.to_html().as_str());
buffer.push_str(format!("<span class=\"boolean\">{}</span>", self.value).as_str());
buffer.push_str("</span>");
buffer.push_str(self.line_terminator0.to_html().as_str());
buffer
}
}

impl Htmlable for MultipartParam {
fn to_html(&self) -> String {
match self {
Expand Down
1 change: 1 addition & 0 deletions packages/hurl_core/src/parser/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub enum ParseError {
InvalidCookieAttribute,
OddNumberOfHexDigits,
UrlIllegalCharacter(char),
InvalidOption,
}

impl Error {
Expand Down
Loading