Create http::header module.

This commit is contained in:
jcamiel 2022-06-21 18:33:02 +02:00 committed by Fabrice Reix
parent 3b801a782a
commit 451f6e8200
11 changed files with 85 additions and 76 deletions

View File

@ -28,7 +28,7 @@ use super::options::ClientOptions;
use super::request::*;
use super::request_spec::*;
use super::response::*;
use crate::http::{HttpError, Verbosity};
use super::{Header, HttpError, Verbosity};
use std::str::FromStr;
use url::Url;
@ -310,7 +310,7 @@ impl Client {
.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 {
list.append(format!("Content-Type: {}", s).as_str())
.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
}
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 {
Some(ref u) => u.clone(),
None => format!("hurl/{}", clap::crate_version!()),
@ -334,14 +334,12 @@ impl Client {
if let Some(ref user) = self.options.user {
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())
.unwrap();
}
}
if self.options.compressed
&& get_header_values(&request.headers, "Accept-Encoding").is_empty()
{
if self.options.compressed && request.get_header_values("Accept-Encoding").is_empty() {
list.append("Accept-Encoding: gzip, deflate, br").unwrap();
}
@ -468,7 +466,7 @@ impl Client {
if !(300..400).contains(&response_code) {
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,
Some(value) => value.clone(),
};

View File

@ -19,12 +19,6 @@
use core::fmt;
use std::str::FromStr;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Header {
pub name: String,
pub value: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Cookie {
pub domain: String,
@ -49,12 +43,6 @@ pub struct Param {
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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)]
mod tests {
use super::*;

View 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()
}

View File

@ -18,8 +18,9 @@
pub use self::client::Client;
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::header::Header;
pub use self::options::{ClientOptions, Verbosity};
pub use self::request::Request;
#[cfg(test)]
@ -34,6 +35,7 @@ mod client;
mod cookie;
mod core;
mod error;
mod header;
mod options;
mod request;
mod request_spec;

View File

@ -17,6 +17,7 @@
*/
use super::core::*;
use super::Header;
use url::Url;
#[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -16,6 +16,7 @@
*
*/
use super::{header, Header};
use core::fmt;
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let value = match self {

View File

@ -16,11 +16,10 @@
*
*/
use super::{header, Header};
use core::fmt;
use std::time::Duration;
use super::core::*;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Response {
pub version: Version,
@ -49,34 +48,16 @@ impl fmt::Display for Version {
}
impl Response {
///
/// return a list of headers values for the given header name
///
pub fn get_header_values(&self, expected_name: String) -> Vec<String> {
get_header_values(&self.headers, &expected_name)
/// Returns all header values.
pub fn get_header_values(&self, name: &str) -> Vec<String> {
header::get_values(&self.headers, name)
}
///
///
///
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
///
/// Returns optional Content-type header value.
pub fn content_type(&self) -> Option<String> {
for header in self.headers.clone() {
if header.name.to_lowercase().as_str() == "content-type" {
return Some(header.value);
}
}
None
header::get_values(&self.headers, "Content-Type")
.get(0)
.cloned()
}
}
@ -253,9 +234,9 @@ xxx
duration: Default::default(),
};
assert_eq!(
response.get_header_values("Content-Length".to_string()),
response.get_header_values("Content-Length"),
vec!["12".to_string()]
);
assert!(response.get_header_values("Unknown".to_string()).is_empty());
assert!(response.get_header_values("Unknown").is_empty());
}
}

View File

@ -15,8 +15,8 @@
* limitations under the License.
*
*/
use crate::http::Response;
use crate::http::ResponseCookie;
use super::Response;
use super::ResponseCookie;
impl Response {
pub fn cookies(&self) -> Vec<ResponseCookie> {

View File

@ -60,7 +60,7 @@ pub fn eval_query_value(
QueryValue::Status {} => Ok(Some(Value::Integer(i64::from(http_response.status)))),
QueryValue::Header { name, .. } => {
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() {
Ok(None)
} else if values.len() == 1 {

View File

@ -72,7 +72,7 @@ pub fn eval_asserts(
}
Ok(expected) => {
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() {
asserts.push(AssertResult::Header {
actual: Err(Error {

View File

@ -67,7 +67,7 @@ fn test_hello() {
name: "Content-Type".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
@ -337,10 +337,7 @@ fn test_redirect() {
assert_eq!(response.status, 302);
assert_eq!(
response
.get_header_values("Location".to_string())
.get(0)
.unwrap(),
response.get_header_values("Location").get(0).unwrap(),
"http://localhost:8000/redirected"
);
assert_eq!(client.redirect_count, 0);