mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-25 03:52:09 +03:00
Create http::header module.
This commit is contained in:
parent
3b801a782a
commit
451f6e8200
@ -28,7 +28,7 @@ use super::options::ClientOptions;
|
|||||||
use super::request::*;
|
use super::request::*;
|
||||||
use super::request_spec::*;
|
use super::request_spec::*;
|
||||||
use super::response::*;
|
use super::response::*;
|
||||||
use crate::http::{HttpError, Verbosity};
|
use super::{Header, HttpError, Verbosity};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ impl Client {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_header_values(&request.headers, "Content-Type").is_empty() {
|
if request.get_header_values("Content-Type").is_empty() {
|
||||||
if let Some(ref s) = request.content_type {
|
if let Some(ref s) = request.content_type {
|
||||||
list.append(format!("Content-Type: {}", s).as_str())
|
list.append(format!("Content-Type: {}", s).as_str())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -319,11 +319,11 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_header_values(&request.headers, "Expect").is_empty() {
|
if request.get_header_values("Expect").is_empty() {
|
||||||
list.append("Expect:").unwrap(); // remove header Expect
|
list.append("Expect:").unwrap(); // remove header Expect
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_header_values(&request.headers, "User-Agent").is_empty() {
|
if request.get_header_values("User-Agent").is_empty() {
|
||||||
let user_agent = match self.options.user_agent {
|
let user_agent = match self.options.user_agent {
|
||||||
Some(ref u) => u.clone(),
|
Some(ref u) => u.clone(),
|
||||||
None => format!("hurl/{}", clap::crate_version!()),
|
None => format!("hurl/{}", clap::crate_version!()),
|
||||||
@ -334,14 +334,12 @@ impl Client {
|
|||||||
|
|
||||||
if let Some(ref user) = self.options.user {
|
if let Some(ref user) = self.options.user {
|
||||||
let authorization = base64::encode(user.as_bytes());
|
let authorization = base64::encode(user.as_bytes());
|
||||||
if get_header_values(&request.headers, "Authorization").is_empty() {
|
if request.get_header_values("Authorization").is_empty() {
|
||||||
list.append(format!("Authorization: Basic {}", authorization).as_str())
|
list.append(format!("Authorization: Basic {}", authorization).as_str())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.options.compressed
|
if self.options.compressed && request.get_header_values("Accept-Encoding").is_empty() {
|
||||||
&& get_header_values(&request.headers, "Accept-Encoding").is_empty()
|
|
||||||
{
|
|
||||||
list.append("Accept-Encoding: gzip, deflate, br").unwrap();
|
list.append("Accept-Encoding: gzip, deflate, br").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +466,7 @@ impl Client {
|
|||||||
if !(300..400).contains(&response_code) {
|
if !(300..400).contains(&response_code) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let location = match get_header_values(&response.headers, "Location").get(0) {
|
let location = match response.get_header_values("Location").get(0) {
|
||||||
None => return None,
|
None => return None,
|
||||||
Some(value) => value.clone(),
|
Some(value) => value.clone(),
|
||||||
};
|
};
|
||||||
|
@ -19,12 +19,6 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct Header {
|
|
||||||
pub name: String,
|
|
||||||
pub value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Cookie {
|
pub struct Cookie {
|
||||||
pub domain: String,
|
pub domain: String,
|
||||||
@ -49,12 +43,6 @@ pub struct Param {
|
|||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Header {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}: {}", self.name, self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Cookie {
|
impl fmt::Display for Cookie {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@ -144,22 +132,6 @@ impl FromStr for Cookie {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
/// Return a list of headers values for the given header name.
|
|
||||||
///
|
|
||||||
pub fn get_header_values(headers: &[Header], expected_name: &str) -> Vec<String> {
|
|
||||||
headers
|
|
||||||
.iter()
|
|
||||||
.filter_map(|Header { name, value }| {
|
|
||||||
if name.to_lowercase() == expected_name.to_lowercase() {
|
|
||||||
Some(value.to_string())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
50
packages/hurl/src/http/header.rs
Normal file
50
packages/hurl/src/http/header.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Hurl (https://hurl.dev)
|
||||||
|
* Copyright (C) 2022 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 core::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Header {
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Header {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}: {}", self.name, self.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all header values for given name
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `headers` - A list of HTTP headers
|
||||||
|
/// * `name` - A name to filter header (case insensitively)
|
||||||
|
pub fn get_values(headers: &[Header], name: &str) -> Vec<String> {
|
||||||
|
headers
|
||||||
|
.iter()
|
||||||
|
.filter_map(|Header { name: key, value }| {
|
||||||
|
if key.to_lowercase() == name.to_lowercase() {
|
||||||
|
Some(value.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
pub use self::client::Client;
|
pub use self::client::Client;
|
||||||
pub use self::cookie::{CookieAttribute, ResponseCookie};
|
pub use self::cookie::{CookieAttribute, ResponseCookie};
|
||||||
pub use self::core::{Cookie, Header, Param, RequestCookie};
|
pub use self::core::{Cookie, Param, RequestCookie};
|
||||||
pub use self::error::HttpError;
|
pub use self::error::HttpError;
|
||||||
|
pub use self::header::Header;
|
||||||
pub use self::options::{ClientOptions, Verbosity};
|
pub use self::options::{ClientOptions, Verbosity};
|
||||||
pub use self::request::Request;
|
pub use self::request::Request;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -34,6 +35,7 @@ mod client;
|
|||||||
mod cookie;
|
mod cookie;
|
||||||
mod core;
|
mod core;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod header;
|
||||||
mod options;
|
mod options;
|
||||||
mod request;
|
mod request;
|
||||||
mod request_spec;
|
mod request_spec;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use super::core::*;
|
use super::core::*;
|
||||||
|
use super::Header;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use super::{header, Header};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use super::core::*;
|
use super::core::*;
|
||||||
@ -77,6 +78,13 @@ impl Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RequestSpec {
|
||||||
|
/// Returns all header values.
|
||||||
|
pub fn get_header_values(&self, name: &str) -> Vec<String> {
|
||||||
|
header::get_values(&self.headers, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Method {
|
impl fmt::Display for Method {
|
||||||
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 {
|
||||||
|
@ -16,11 +16,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use super::{header, Header};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use super::core::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
@ -49,34 +48,16 @@ impl fmt::Display for Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
///
|
/// Returns all header values.
|
||||||
/// return a list of headers values for the given header name
|
pub fn get_header_values(&self, name: &str) -> Vec<String> {
|
||||||
///
|
header::get_values(&self.headers, name)
|
||||||
pub fn get_header_values(&self, expected_name: String) -> Vec<String> {
|
|
||||||
get_header_values(&self.headers, &expected_name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
/// Returns optional Content-type header value.
|
||||||
///
|
|
||||||
///
|
|
||||||
pub fn get_header(&self, name: String) -> Vec<String> {
|
|
||||||
self.headers
|
|
||||||
.iter()
|
|
||||||
.filter(|&h| h.name.to_lowercase() == name.to_lowercase())
|
|
||||||
.map(|h| h.value.clone())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Return optional Content-type header value
|
|
||||||
///
|
|
||||||
pub fn content_type(&self) -> Option<String> {
|
pub fn content_type(&self) -> Option<String> {
|
||||||
for header in self.headers.clone() {
|
header::get_values(&self.headers, "Content-Type")
|
||||||
if header.name.to_lowercase().as_str() == "content-type" {
|
.get(0)
|
||||||
return Some(header.value);
|
.cloned()
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,9 +234,9 @@ xxx
|
|||||||
duration: Default::default(),
|
duration: Default::default(),
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
response.get_header_values("Content-Length".to_string()),
|
response.get_header_values("Content-Length"),
|
||||||
vec!["12".to_string()]
|
vec!["12".to_string()]
|
||||||
);
|
);
|
||||||
assert!(response.get_header_values("Unknown".to_string()).is_empty());
|
assert!(response.get_header_values("Unknown").is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
use crate::http::Response;
|
use super::Response;
|
||||||
use crate::http::ResponseCookie;
|
use super::ResponseCookie;
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub fn cookies(&self) -> Vec<ResponseCookie> {
|
pub fn cookies(&self) -> Vec<ResponseCookie> {
|
||||||
|
@ -60,7 +60,7 @@ pub fn eval_query_value(
|
|||||||
QueryValue::Status {} => Ok(Some(Value::Integer(i64::from(http_response.status)))),
|
QueryValue::Status {} => Ok(Some(Value::Integer(i64::from(http_response.status)))),
|
||||||
QueryValue::Header { name, .. } => {
|
QueryValue::Header { name, .. } => {
|
||||||
let header_name = eval_template(&name, variables)?;
|
let header_name = eval_template(&name, variables)?;
|
||||||
let values = http_response.get_header(header_name);
|
let values = http_response.get_header_values(&header_name);
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else if values.len() == 1 {
|
} else if values.len() == 1 {
|
||||||
|
@ -72,7 +72,7 @@ pub fn eval_asserts(
|
|||||||
}
|
}
|
||||||
Ok(expected) => {
|
Ok(expected) => {
|
||||||
let header_name = header.key.value.clone();
|
let header_name = header.key.value.clone();
|
||||||
let actuals = http_response.get_header(header_name);
|
let actuals = http_response.get_header_values(&header_name);
|
||||||
if actuals.is_empty() {
|
if actuals.is_empty() {
|
||||||
asserts.push(AssertResult::Header {
|
asserts.push(AssertResult::Header {
|
||||||
actual: Err(Error {
|
actual: Err(Error {
|
||||||
|
@ -67,7 +67,7 @@ fn test_hello() {
|
|||||||
name: "Content-Type".to_string(),
|
name: "Content-Type".to_string(),
|
||||||
value: "text/html; charset=utf-8".to_string(),
|
value: "text/html; charset=utf-8".to_string(),
|
||||||
}));
|
}));
|
||||||
assert_eq!(response.get_header_values("Date".to_string()).len(), 1);
|
assert_eq!(response.get_header_values("Date").len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@ -337,10 +337,7 @@ fn test_redirect() {
|
|||||||
|
|
||||||
assert_eq!(response.status, 302);
|
assert_eq!(response.status, 302);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
response
|
response.get_header_values("Location").get(0).unwrap(),
|
||||||
.get_header_values("Location".to_string())
|
|
||||||
.get(0)
|
|
||||||
.unwrap(),
|
|
||||||
"http://localhost:8000/redirected"
|
"http://localhost:8000/redirected"
|
||||||
);
|
);
|
||||||
assert_eq!(client.redirect_count, 0);
|
assert_eq!(client.redirect_count, 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user