mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-09-11 05:35:53 +03:00
Add support for --resolve option per request
This commit is contained in:
parent
4f6a00170a
commit
1463c02d05
@ -120,6 +120,7 @@ option:
|
||||
| follow-redirect-option
|
||||
| insecure-option
|
||||
| max-redirs-option
|
||||
| resolve-option
|
||||
| retry-option
|
||||
| retry-interval-option
|
||||
| variable-option
|
||||
@ -135,6 +136,8 @@ insecure-option: "insecure" ":" boolean lt
|
||||
|
||||
max-redirs-option: "max-redirs" ":" integer lt
|
||||
|
||||
resolve-option: "resolve" ":" quoted-string lt
|
||||
|
||||
retry-option: "retry" ":" boolean lt
|
||||
|
||||
retry-interval-option: "retry-interval" ":" integer lt
|
||||
|
3
integration/tests_ok/resolve_option.curl
Normal file
3
integration/tests_ok/resolve_option.curl
Normal file
@ -0,0 +1,3 @@
|
||||
curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://foo.com:8000/resolve'
|
||||
curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://bar.com:8000/resolve'
|
||||
curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://baz.com:8000/resolve'
|
20
integration/tests_ok/resolve_option.hurl
Normal file
20
integration/tests_ok/resolve_option.hurl
Normal file
@ -0,0 +1,20 @@
|
||||
# --resolve option allow to us custom address for a specific host and port pair.
|
||||
GET http://foo.com:8000/resolve
|
||||
[Options]
|
||||
resolve: foo.com:8000:127.0.0.1
|
||||
HTTP 200
|
||||
`Hello World!`
|
||||
|
||||
|
||||
GET http://bar.com:8000/resolve
|
||||
[Options]
|
||||
resolve: bar.com:8000:127.0.0.1
|
||||
HTTP 200
|
||||
`Hello World!`
|
||||
|
||||
|
||||
GET http://baz.com:8000/resolve
|
||||
[Options]
|
||||
resolve: baz.com:8000:127.0.0.1
|
||||
HTTP 200
|
||||
`Hello World!`
|
1
integration/tests_ok/resolve_option.out
Normal file
1
integration/tests_ok/resolve_option.out
Normal file
@ -0,0 +1 @@
|
||||
Hello World!
|
3
integration/tests_ok/resolve_option.ps1
Normal file
3
integration/tests_ok/resolve_option.ps1
Normal file
@ -0,0 +1,3 @@
|
||||
Set-StrictMode -Version latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
hurl tests_ok/resolve_option.hurl --verbose
|
3
integration/tests_ok/resolve_option.sh
Executable file
3
integration/tests_ok/resolve_option.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
hurl tests_ok/resolve_option.hurl --verbose
|
@ -26,7 +26,6 @@ use crate::runner::core::{Error, RunnerError, *};
|
||||
use crate::runner::request::{cookie_storage_clear, cookie_storage_set, eval_request};
|
||||
use crate::runner::response::{eval_asserts, eval_captures, eval_version_status_asserts};
|
||||
use crate::runner::runner_options::RunnerOptions;
|
||||
use crate::runner::template::eval_template;
|
||||
use crate::runner::value::Value;
|
||||
use crate::util::logger::{Logger, Verbosity};
|
||||
|
||||
@ -285,144 +284,3 @@ fn log_request_spec(request: &http::RequestSpec, logger: &Logger) {
|
||||
}
|
||||
logger.debug("");
|
||||
}
|
||||
|
||||
/// Returns a new [`RunnerOptions`] based on the `entry` optional Options section
|
||||
/// and a default `runner_options`.
|
||||
/// The [`variables`] can also be updated if `variable` keys are present in the section.
|
||||
pub fn get_entry_options(
|
||||
entry: &Entry,
|
||||
runner_options: &RunnerOptions,
|
||||
variables: &mut HashMap<String, Value>,
|
||||
logger: &Logger,
|
||||
) -> Result<RunnerOptions, Error> {
|
||||
let mut runner_options = runner_options.clone();
|
||||
if !has_options(entry) {
|
||||
return Ok(runner_options);
|
||||
}
|
||||
|
||||
logger.debug("");
|
||||
logger.debug_important("Entry options:");
|
||||
|
||||
for section in &entry.request.sections {
|
||||
if let SectionValue::Options(options) = §ion.value {
|
||||
for option in options {
|
||||
match option {
|
||||
EntryOption::CaCertificate(option) => {
|
||||
runner_options.cacert_file = Some(option.filename.value.clone());
|
||||
logger.debug(format!("cacert: {}", option.filename.value).as_str());
|
||||
}
|
||||
EntryOption::ClientCert(option) => {
|
||||
runner_options.client_cert_file = Some(option.filename.value.clone());
|
||||
logger.debug(format!("cert: {}", option.filename.value).as_str());
|
||||
}
|
||||
EntryOption::ClientKey(option) => {
|
||||
runner_options.client_key_file = Some(option.filename.value.clone());
|
||||
logger.debug(format!("key: {}", option.filename.value).as_str());
|
||||
}
|
||||
EntryOption::Compressed(option) => {
|
||||
runner_options.compressed = option.value;
|
||||
logger.debug(format!("compressed: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::FollowLocation(option) => {
|
||||
runner_options.follow_location = option.value;
|
||||
logger.debug(format!("location: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Insecure(option) => {
|
||||
runner_options.insecure = option.value;
|
||||
logger.debug(format!("insecure: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::MaxRedirect(option) => {
|
||||
runner_options.max_redirect = Some(option.value);
|
||||
logger.debug(format!("max-redirs: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::PathAsIs(option) => {
|
||||
runner_options.path_as_is = option.value;
|
||||
logger.debug(format!("path-as-is: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Proxy(option) => {
|
||||
runner_options.proxy = Some(option.value.clone());
|
||||
logger.debug(format!("proxy: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Retry(option) => {
|
||||
runner_options.retry = option.value;
|
||||
logger.debug(format!("retry: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::RetryInterval(option) => {
|
||||
runner_options.retry_interval = Duration::from_millis(option.value);
|
||||
logger.debug(format!("retry-interval: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Variable(VariableOption {
|
||||
value: VariableDefinition { name, value, .. },
|
||||
..
|
||||
}) => {
|
||||
let value = eval_variable_value(value, variables)?;
|
||||
variables.insert(name.clone(), value);
|
||||
}
|
||||
EntryOption::Verbose(option) => {
|
||||
logger.debug(format!("verbose: {}", option.value).as_str());
|
||||
}
|
||||
|
||||
EntryOption::VeryVerbose(option) => {
|
||||
logger.debug(format!("very-verbose: {}", option.value).as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(runner_options)
|
||||
}
|
||||
|
||||
fn eval_variable_value(
|
||||
variable_value: &VariableValue,
|
||||
variables: &mut HashMap<String, Value>,
|
||||
) -> Result<Value, Error> {
|
||||
match variable_value {
|
||||
VariableValue::Null {} => Ok(Value::Null),
|
||||
VariableValue::Bool(v) => Ok(Value::Bool(*v)),
|
||||
VariableValue::Integer(v) => Ok(Value::Integer(*v)),
|
||||
VariableValue::Float(Float { value, .. }) => Ok(Value::Float(*value)),
|
||||
VariableValue::String(template) => {
|
||||
let s = eval_template(template, variables)?;
|
||||
Ok(Value::String(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [`true`] if this `entry` has an Option section, [`false`] otherwise.
|
||||
fn has_options(entry: &Entry) -> bool {
|
||||
entry
|
||||
.request
|
||||
.sections
|
||||
.iter()
|
||||
.any(|s| matches!(s.value, SectionValue::Options(_)))
|
||||
}
|
||||
|
||||
/// Returns the overridden `entry` verbosity, or the default `verbosity` file.
|
||||
pub fn get_entry_verbosity(entry: &Entry, verbosity: &Option<Verbosity>) -> Option<Verbosity> {
|
||||
let mut verbosity = *verbosity;
|
||||
|
||||
for section in &entry.request.sections {
|
||||
if let SectionValue::Options(options) = §ion.value {
|
||||
for option in options {
|
||||
match option {
|
||||
EntryOption::Verbose(option) => {
|
||||
verbosity = if option.value {
|
||||
Some(Verbosity::Verbose)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
EntryOption::VeryVerbose(option) => {
|
||||
verbosity = if option.value {
|
||||
Some(Verbosity::VeryVerbose)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
verbosity
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ use crate::http;
|
||||
use crate::http::Call;
|
||||
use crate::runner::core::*;
|
||||
use crate::runner::runner_options::RunnerOptions;
|
||||
use crate::runner::{entry, Value};
|
||||
use crate::runner::{entry, options, Value};
|
||||
use crate::util::logger::{ErrorFormat, Logger, LoggerOptions, LoggerOptionsBuilder};
|
||||
|
||||
/// Runs a Hurl `content` and returns a [`HurlResult`] upon completion.
|
||||
@ -130,7 +130,7 @@ pub fn run(
|
||||
logger.test_progress(entry_index, n);
|
||||
|
||||
// The real execution of the entry happens here, with the overridden entry options.
|
||||
let options = entry::get_entry_options(entry, runner_options, &mut variables, &logger);
|
||||
let options = options::get_entry_options(entry, runner_options, &mut variables, &logger);
|
||||
let entry_result = match &options {
|
||||
Ok(options) => entry::run(
|
||||
entry,
|
||||
@ -366,7 +366,7 @@ fn log_errors(entry_result: &EntryResult, content: &str, retry: bool, logger: &L
|
||||
/// Verbosity can be overridden at entry level with an Options section so each
|
||||
/// entry has its own logger.
|
||||
fn get_entry_logger(entry: &Entry, logger_options: &LoggerOptions) -> Logger {
|
||||
let entry_verbosity = entry::get_entry_verbosity(entry, &logger_options.verbosity);
|
||||
let entry_verbosity = options::get_entry_verbosity(entry, &logger_options.verbosity);
|
||||
let entry_logger_options = LoggerOptionsBuilder::new()
|
||||
.color(logger_options.color)
|
||||
.filename(&logger_options.filename)
|
||||
|
@ -40,6 +40,7 @@ mod hurl_file;
|
||||
mod json;
|
||||
mod multiline;
|
||||
mod multipart;
|
||||
mod options;
|
||||
mod predicate;
|
||||
mod predicate_value;
|
||||
mod query;
|
||||
|
174
packages/hurl/src/runner/options.rs
Normal file
174
packages/hurl/src/runner/options.rs
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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::runner::template;
|
||||
use crate::runner::{Error, RunnerOptions, Value};
|
||||
use crate::util::logger::{Logger, Verbosity};
|
||||
use hurl_core::ast::{
|
||||
Entry, EntryOption, Float, SectionValue, VariableDefinition, VariableOption, VariableValue,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Returns a new [`RunnerOptions`] based on the `entry` optional Options section
|
||||
/// and a default `runner_options`.
|
||||
/// The [`variables`] can also be updated if `variable` keys are present in the section.
|
||||
pub fn get_entry_options(
|
||||
entry: &Entry,
|
||||
runner_options: &RunnerOptions,
|
||||
variables: &mut HashMap<String, Value>,
|
||||
logger: &Logger,
|
||||
) -> Result<RunnerOptions, Error> {
|
||||
let mut runner_options = runner_options.clone();
|
||||
if !has_options(entry) {
|
||||
return Ok(runner_options);
|
||||
}
|
||||
|
||||
logger.debug("");
|
||||
logger.debug_important("Entry options:");
|
||||
|
||||
for section in &entry.request.sections {
|
||||
if let SectionValue::Options(options) = §ion.value {
|
||||
for option in options {
|
||||
match option {
|
||||
EntryOption::CaCertificate(option) => {
|
||||
runner_options.cacert_file = Some(option.filename.value.clone());
|
||||
logger.debug(format!("cacert: {}", option.filename.value).as_str());
|
||||
}
|
||||
EntryOption::ClientCert(option) => {
|
||||
runner_options.client_cert_file = Some(option.filename.value.clone());
|
||||
logger.debug(format!("cert: {}", option.filename.value).as_str());
|
||||
}
|
||||
EntryOption::ClientKey(option) => {
|
||||
runner_options.client_key_file = Some(option.filename.value.clone());
|
||||
logger.debug(format!("key: {}", option.filename.value).as_str());
|
||||
}
|
||||
EntryOption::Compressed(option) => {
|
||||
runner_options.compressed = option.value;
|
||||
logger.debug(format!("compressed: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::FollowLocation(option) => {
|
||||
runner_options.follow_location = option.value;
|
||||
logger.debug(format!("location: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Insecure(option) => {
|
||||
runner_options.insecure = option.value;
|
||||
logger.debug(format!("insecure: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::MaxRedirect(option) => {
|
||||
runner_options.max_redirect = Some(option.value);
|
||||
logger.debug(format!("max-redirs: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::PathAsIs(option) => {
|
||||
runner_options.path_as_is = option.value;
|
||||
logger.debug(format!("path-as-is: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Proxy(option) => {
|
||||
runner_options.proxy = Some(option.value.clone());
|
||||
logger.debug(format!("proxy: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Resolve(option) => {
|
||||
let mut resolves = runner_options.resolves;
|
||||
resolves.push(option.value.clone());
|
||||
runner_options.resolves = resolves;
|
||||
logger.debug(format!("resolve: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Retry(option) => {
|
||||
runner_options.retry = option.value;
|
||||
logger.debug(format!("retry: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::RetryInterval(option) => {
|
||||
runner_options.retry_interval = Duration::from_millis(option.value);
|
||||
logger.debug(format!("retry-interval: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Variable(VariableOption {
|
||||
value: VariableDefinition { name, value, .. },
|
||||
..
|
||||
}) => {
|
||||
let value = eval_variable_value(value, variables)?;
|
||||
logger.debug(format!("variable: {}={}", name, value).as_str());
|
||||
variables.insert(name.clone(), value);
|
||||
}
|
||||
EntryOption::Verbose(option) => {
|
||||
logger.debug(format!("verbose: {}", option.value).as_str());
|
||||
}
|
||||
|
||||
EntryOption::VeryVerbose(option) => {
|
||||
logger.debug(format!("very-verbose: {}", option.value).as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(runner_options)
|
||||
}
|
||||
|
||||
/// Returns [`true`] if this `entry` has an Option section, [`false`] otherwise.
|
||||
fn has_options(entry: &Entry) -> bool {
|
||||
entry
|
||||
.request
|
||||
.sections
|
||||
.iter()
|
||||
.any(|s| matches!(s.value, SectionValue::Options(_)))
|
||||
}
|
||||
|
||||
/// Returns the overridden `entry` verbosity, or the default `verbosity` file.
|
||||
pub fn get_entry_verbosity(entry: &Entry, verbosity: &Option<Verbosity>) -> Option<Verbosity> {
|
||||
let mut verbosity = *verbosity;
|
||||
|
||||
for section in &entry.request.sections {
|
||||
if let SectionValue::Options(options) = §ion.value {
|
||||
for option in options {
|
||||
match option {
|
||||
EntryOption::Verbose(option) => {
|
||||
verbosity = if option.value {
|
||||
Some(Verbosity::Verbose)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
EntryOption::VeryVerbose(option) => {
|
||||
verbosity = if option.value {
|
||||
Some(Verbosity::VeryVerbose)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
verbosity
|
||||
}
|
||||
|
||||
fn eval_variable_value(
|
||||
variable_value: &VariableValue,
|
||||
variables: &mut HashMap<String, Value>,
|
||||
) -> Result<Value, Error> {
|
||||
match variable_value {
|
||||
VariableValue::Null {} => Ok(Value::Null),
|
||||
VariableValue::Bool(v) => Ok(Value::Bool(*v)),
|
||||
VariableValue::Integer(v) => Ok(Value::Integer(*v)),
|
||||
VariableValue::Float(Float { value, .. }) => Ok(Value::Float(*value)),
|
||||
VariableValue::String(template) => {
|
||||
let s = template::eval_template(template, variables)?;
|
||||
Ok(Value::String(s))
|
||||
}
|
||||
}
|
||||
}
|
@ -717,6 +717,7 @@ pub enum EntryOption {
|
||||
MaxRedirect(MaxRedirectOption),
|
||||
PathAsIs(PathAsIsOption),
|
||||
Proxy(ProxyOption),
|
||||
Resolve(ResolveOption),
|
||||
Retry(RetryOption),
|
||||
RetryInterval(RetryIntervalOption),
|
||||
Variable(VariableOption),
|
||||
@ -804,6 +805,16 @@ pub struct RetryIntervalOption {
|
||||
pub line_terminator0: LineTerminator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ResolveOption {
|
||||
pub line_terminators: Vec<LineTerminator>,
|
||||
pub space0: Whitespace,
|
||||
pub space1: Whitespace,
|
||||
pub space2: Whitespace,
|
||||
pub value: String,
|
||||
pub line_terminator0: LineTerminator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct RetryOption {
|
||||
pub line_terminators: Vec<LineTerminator>,
|
||||
|
@ -211,6 +211,7 @@ impl HtmlFormatter {
|
||||
EntryOption::MaxRedirect(option) => self.fmt_max_redirect_option(option),
|
||||
EntryOption::PathAsIs(option) => self.fmt_path_as_is_option(option),
|
||||
EntryOption::Proxy(option) => self.fmt_proxy_option(option),
|
||||
EntryOption::Resolve(option) => self.fmt_resolve_option(option),
|
||||
EntryOption::Retry(option) => self.fmt_retry_option(option),
|
||||
EntryOption::RetryInterval(option) => self.fmt_retry_interval_option(option),
|
||||
EntryOption::Variable(option) => self.fmt_variable_option(option),
|
||||
@ -336,6 +337,19 @@ impl HtmlFormatter {
|
||||
self.fmt_lt(&option.line_terminator0);
|
||||
}
|
||||
|
||||
fn fmt_resolve_option(&mut self, option: &ResolveOption) {
|
||||
self.fmt_lts(&option.line_terminators);
|
||||
self.fmt_span_open("line");
|
||||
self.fmt_space(&option.space0);
|
||||
self.fmt_string("resolve");
|
||||
self.fmt_space(&option.space1);
|
||||
self.buffer.push(':');
|
||||
self.fmt_space(&option.space2);
|
||||
self.fmt_string(&option.value);
|
||||
self.fmt_span_close();
|
||||
self.fmt_lt(&option.line_terminator0);
|
||||
}
|
||||
|
||||
fn fmt_retry_option(&mut self, option: &RetryOption) {
|
||||
self.fmt_lts(&option.line_terminators);
|
||||
self.fmt_span_open("line");
|
||||
|
@ -366,6 +366,7 @@ fn option(reader: &mut Reader) -> ParseResult<'static, EntryOption> {
|
||||
option_max_redirect,
|
||||
option_path_as_is,
|
||||
option_proxy,
|
||||
option_resolve,
|
||||
option_retry,
|
||||
option_retry_interval,
|
||||
option_variable,
|
||||
@ -589,6 +590,50 @@ fn proxy(reader: &mut Reader) -> ParseResult<'static, String> {
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
fn option_resolve(reader: &mut Reader) -> ParseResult<'static, EntryOption> {
|
||||
let line_terminators = optional_line_terminators(reader)?;
|
||||
let space0 = zero_or_more_spaces(reader)?;
|
||||
try_literal("resolve", reader)?;
|
||||
let space1 = zero_or_more_spaces(reader)?;
|
||||
try_literal(":", reader)?;
|
||||
let space2 = zero_or_more_spaces(reader)?;
|
||||
let value = resolve(reader)?;
|
||||
let line_terminator0 = line_terminator(reader)?;
|
||||
let option = ResolveOption {
|
||||
line_terminators,
|
||||
space0,
|
||||
space1,
|
||||
space2,
|
||||
value,
|
||||
line_terminator0,
|
||||
};
|
||||
Ok(EntryOption::Resolve(option))
|
||||
}
|
||||
|
||||
fn resolve(reader: &mut Reader) -> ParseResult<'static, String> {
|
||||
let start = reader.state.clone();
|
||||
let name = reader.read_while(|c| c.is_alphanumeric() || *c == ':' || *c == '.');
|
||||
if name.is_empty() {
|
||||
return Err(Error {
|
||||
pos: start.pos,
|
||||
recoverable: false,
|
||||
inner: ParseError::Expecting {
|
||||
value: "resolve".to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
if !name.contains(':') {
|
||||
return Err(Error {
|
||||
pos: start.pos,
|
||||
recoverable: false,
|
||||
inner: ParseError::Expecting {
|
||||
value: "HOST:PORT:ADDR".to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
fn option_retry(reader: &mut Reader) -> ParseResult<'static, EntryOption> {
|
||||
let line_terminators = optional_line_terminators(reader)?;
|
||||
let space0 = zero_or_more_spaces(reader)?;
|
||||
|
@ -272,74 +272,78 @@ impl ToJson for Cookie {
|
||||
impl ToJson for EntryOption {
|
||||
fn to_json(&self) -> JValue {
|
||||
let attributes = match self {
|
||||
EntryOption::CaCertificate(value) => vec![
|
||||
EntryOption::CaCertificate(value) => [
|
||||
("name".to_string(), JValue::String("cacert".to_string())),
|
||||
(
|
||||
"value".to_string(),
|
||||
JValue::String(value.filename.value.clone()),
|
||||
),
|
||||
],
|
||||
EntryOption::ClientCert(value) => vec![
|
||||
EntryOption::ClientCert(value) => [
|
||||
("name".to_string(), JValue::String("cert".to_string())),
|
||||
(
|
||||
"value".to_string(),
|
||||
JValue::String(value.filename.value.clone()),
|
||||
),
|
||||
],
|
||||
EntryOption::ClientKey(value) => vec![
|
||||
EntryOption::ClientKey(value) => [
|
||||
("name".to_string(), JValue::String("key".to_string())),
|
||||
(
|
||||
"value".to_string(),
|
||||
JValue::String(value.filename.value.clone()),
|
||||
),
|
||||
],
|
||||
EntryOption::Compressed(value) => vec![
|
||||
EntryOption::Compressed(value) => [
|
||||
("name".to_string(), JValue::String("compressed".to_string())),
|
||||
("value".to_string(), JValue::Boolean(value.value)),
|
||||
],
|
||||
EntryOption::Insecure(value) => vec![
|
||||
EntryOption::Insecure(value) => [
|
||||
("name".to_string(), JValue::String("insecure".to_string())),
|
||||
("value".to_string(), JValue::Boolean(value.value)),
|
||||
],
|
||||
EntryOption::FollowLocation(value) => vec![
|
||||
EntryOption::FollowLocation(value) => [
|
||||
("name".to_string(), JValue::String("location".to_string())),
|
||||
("value".to_string(), JValue::Boolean(value.value)),
|
||||
],
|
||||
EntryOption::MaxRedirect(value) => vec![
|
||||
EntryOption::MaxRedirect(value) => [
|
||||
("name".to_string(), JValue::String("max-redirs".to_string())),
|
||||
("value".to_string(), JValue::Number(value.value.to_string())),
|
||||
],
|
||||
EntryOption::PathAsIs(value) => vec![
|
||||
EntryOption::PathAsIs(value) => [
|
||||
("name".to_string(), JValue::String("path-as-is".to_string())),
|
||||
("value".to_string(), JValue::Boolean(value.value)),
|
||||
],
|
||||
EntryOption::Proxy(value) => vec![
|
||||
EntryOption::Proxy(value) => [
|
||||
("name".to_string(), JValue::String("proxy".to_string())),
|
||||
("value".to_string(), JValue::String(value.value.clone())),
|
||||
],
|
||||
EntryOption::Retry(value) => vec![
|
||||
EntryOption::Resolve(value) => [
|
||||
("name".to_string(), JValue::String("resolve".to_string())),
|
||||
("value".to_string(), JValue::Number(value.value.to_string())),
|
||||
],
|
||||
EntryOption::Retry(value) => [
|
||||
("name".to_string(), JValue::String("retry".to_string())),
|
||||
("value".to_string(), JValue::Number(value.value.to_string())),
|
||||
],
|
||||
EntryOption::RetryInterval(value) => vec![
|
||||
EntryOption::RetryInterval(value) => [
|
||||
(
|
||||
"name".to_string(),
|
||||
JValue::String("retry-interval".to_string()),
|
||||
),
|
||||
("value".to_string(), JValue::Number(value.value.to_string())),
|
||||
],
|
||||
EntryOption::Variable(value) => vec![
|
||||
EntryOption::Variable(value) => [
|
||||
("name".to_string(), JValue::String("variable".to_string())),
|
||||
(
|
||||
"value".to_string(),
|
||||
JValue::String(format!("{}={}", value.value.name, value.value.value)),
|
||||
),
|
||||
],
|
||||
EntryOption::Verbose(value) => vec![
|
||||
EntryOption::Verbose(value) => [
|
||||
("name".to_string(), JValue::String("verbose".to_string())),
|
||||
("value".to_string(), JValue::Boolean(value.value)),
|
||||
],
|
||||
EntryOption::VeryVerbose(value) => vec![
|
||||
EntryOption::VeryVerbose(value) => [
|
||||
(
|
||||
"name".to_string(),
|
||||
JValue::String("very-verbose".to_string()),
|
||||
@ -347,7 +351,7 @@ impl ToJson for EntryOption {
|
||||
("value".to_string(), JValue::Boolean(value.value)),
|
||||
],
|
||||
};
|
||||
JValue::Object(attributes)
|
||||
JValue::Object(attributes.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -865,6 +865,7 @@ impl Tokenizable for EntryOption {
|
||||
EntryOption::MaxRedirect(option) => option.tokenize(),
|
||||
EntryOption::PathAsIs(option) => option.tokenize(),
|
||||
EntryOption::Proxy(option) => option.tokenize(),
|
||||
EntryOption::Resolve(option) => option.tokenize(),
|
||||
EntryOption::Retry(option) => option.tokenize(),
|
||||
EntryOption::RetryInterval(option) => option.tokenize(),
|
||||
EntryOption::Variable(option) => option.tokenize(),
|
||||
@ -1063,6 +1064,27 @@ impl Tokenizable for ProxyOption {
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for ResolveOption {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
tokens.append(
|
||||
&mut self
|
||||
.line_terminators
|
||||
.iter()
|
||||
.flat_map(|e| e.tokenize())
|
||||
.collect(),
|
||||
);
|
||||
tokens.append(&mut self.space0.tokenize());
|
||||
tokens.push(Token::String("resolve".to_string()));
|
||||
tokens.append(&mut self.space1.tokenize());
|
||||
tokens.push(Token::Colon(String::from(":")));
|
||||
tokens.append(&mut self.space2.tokenize());
|
||||
tokens.push(Token::String(self.value.clone()));
|
||||
tokens.append(&mut self.line_terminator0.tokenize());
|
||||
tokens
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for RetryOption {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
|
Loading…
Reference in New Issue
Block a user