mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-23 00:44:55 +03:00
Use HeaderVec in http::Response.
This commit is contained in:
parent
dd3068cd73
commit
a0dffe429a
@ -30,7 +30,7 @@ use url::Url;
|
||||
use crate::http::certificate::Certificate;
|
||||
use crate::http::core::*;
|
||||
use crate::http::header::{
|
||||
HeaderVec, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_TYPE, EXPECT, USER_AGENT,
|
||||
HeaderVec, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_TYPE, EXPECT, LOCATION, USER_AGENT,
|
||||
};
|
||||
use crate::http::options::ClientOptions;
|
||||
use crate::http::request::*;
|
||||
@ -676,8 +676,8 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Parse headers from libcurl responses.
|
||||
fn parse_response_headers(&mut self, lines: &[String]) -> Vec<Header> {
|
||||
let mut headers: Vec<Header> = vec![];
|
||||
fn parse_response_headers(&mut self, lines: &[String]) -> HeaderVec {
|
||||
let mut headers = HeaderVec::new();
|
||||
for line in lines {
|
||||
if let Some(header) = Header::parse(line) {
|
||||
headers.push(header);
|
||||
@ -697,16 +697,10 @@ impl Client {
|
||||
if !(300..400).contains(&response_code) {
|
||||
return None;
|
||||
}
|
||||
let location = match response.get_header_values("Location").first() {
|
||||
None => return None,
|
||||
Some(value) => get_redirect_url(value, base_url),
|
||||
};
|
||||
|
||||
if location.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(location)
|
||||
}
|
||||
response
|
||||
.headers
|
||||
.get(LOCATION)
|
||||
.map(|h| get_redirect_url(&h.value, base_url))
|
||||
}
|
||||
|
||||
/// Returns cookie storage.
|
||||
|
@ -23,6 +23,7 @@ pub const AUTHORIZATION: &str = "Authorization";
|
||||
pub const COOKIE: &str = "Cookie";
|
||||
pub const CONTENT_TYPE: &str = "Content-Type";
|
||||
pub const EXPECT: &str = "Expect";
|
||||
pub const LOCATION: &str = "Location";
|
||||
pub const USER_AGENT: &str = "User-Agent";
|
||||
|
||||
/// Represents an HTTP header
|
||||
@ -47,20 +48,6 @@ impl Header {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all `headers` values for given `name`.
|
||||
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()
|
||||
}
|
||||
|
||||
/// Represents an ordered list of [`Header`].
|
||||
/// The headers are sorted by insertion order.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
|
@ -20,7 +20,7 @@ use std::time::Duration;
|
||||
|
||||
use crate::http::certificate::Certificate;
|
||||
use crate::http::header::CONTENT_TYPE;
|
||||
use crate::http::{header, Header};
|
||||
use crate::http::HeaderVec;
|
||||
|
||||
/// Represents a runtime HTTP response.
|
||||
/// This is a real response, that has been executed by our HTTP client.
|
||||
@ -28,7 +28,7 @@ use crate::http::{header, Header};
|
||||
pub struct Response {
|
||||
pub version: HttpVersion,
|
||||
pub status: u32,
|
||||
pub headers: Vec<Header>,
|
||||
pub headers: HeaderVec,
|
||||
pub body: Vec<u8>,
|
||||
pub duration: Duration,
|
||||
pub url: String,
|
||||
@ -41,7 +41,7 @@ impl Default for Response {
|
||||
Response {
|
||||
version: HttpVersion::Http10,
|
||||
status: 200,
|
||||
headers: vec![],
|
||||
headers: HeaderVec::new(),
|
||||
body: vec![],
|
||||
duration: Default::default(),
|
||||
url: String::new(),
|
||||
@ -55,7 +55,7 @@ impl Response {
|
||||
pub fn new(
|
||||
version: HttpVersion,
|
||||
status: u32,
|
||||
headers: Vec<Header>,
|
||||
headers: HeaderVec,
|
||||
body: Vec<u8>,
|
||||
duration: Duration,
|
||||
url: &str,
|
||||
@ -73,15 +73,17 @@ impl Response {
|
||||
}
|
||||
|
||||
/// Returns all header values.
|
||||
pub fn get_header_values(&self, name: &str) -> Vec<String> {
|
||||
header::get_values(&self.headers, name)
|
||||
pub fn get_header_values(&self, name: &str) -> Vec<&str> {
|
||||
self.headers
|
||||
.get_all(name)
|
||||
.iter()
|
||||
.map(|h| h.value.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
/// Returns optional Content-type header value.
|
||||
pub fn content_type(&self) -> Option<String> {
|
||||
header::get_values(&self.headers, CONTENT_TYPE)
|
||||
.first()
|
||||
.cloned()
|
||||
pub fn content_type(&self) -> Option<&str> {
|
||||
self.headers.get(CONTENT_TYPE).map(|h| h.value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,17 +112,18 @@ impl fmt::Display for HttpVersion {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::Header;
|
||||
|
||||
#[test]
|
||||
fn get_header_values() {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Length", "12"));
|
||||
|
||||
let response = Response {
|
||||
headers: vec![Header::new("Content-Length", "12")],
|
||||
headers,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
response.get_header_values("Content-Length"),
|
||||
vec!["12".to_string()]
|
||||
);
|
||||
assert_eq!(response.get_header_values("Content-Length"), vec!["12"]);
|
||||
assert!(response.get_header_values("Unknown").is_empty());
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ impl Response {
|
||||
// If it ok, we print each line of the body in debug format. Otherwise, we
|
||||
// print the body first 64 bytes.
|
||||
if let Some(content_type) = self.content_type() {
|
||||
if !mimetype::is_kind_of_text(&content_type) {
|
||||
if !mimetype::is_kind_of_text(content_type) {
|
||||
debug::log_bytes(&self.body, 64, debug, logger);
|
||||
return;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl Response {
|
||||
/// Returns character encoding of the HTTP response.
|
||||
fn character_encoding(&self) -> Result<EncodingRef, HttpError> {
|
||||
match self.content_type() {
|
||||
Some(content_type) => match mimetype::charset(&content_type) {
|
||||
Some(content_type) => match mimetype::charset(content_type) {
|
||||
Some(charset) => {
|
||||
match encoding::label::encoding_from_whatwg_label(charset.as_str()) {
|
||||
None => Err(HttpError::InvalidCharset { charset }),
|
||||
@ -91,10 +91,7 @@ impl Response {
|
||||
|
||||
/// Returns true if response is an HTML response.
|
||||
pub fn is_html(&self) -> bool {
|
||||
match self.content_type() {
|
||||
None => false,
|
||||
Some(s) => mimetype::is_html(&s),
|
||||
}
|
||||
self.content_type().map_or(false, mimetype::is_html)
|
||||
}
|
||||
|
||||
/// Returns list of content encoding from HTTP response headers.
|
||||
@ -179,7 +176,7 @@ fn uncompress_zlib(data: &[u8]) -> Result<Vec<u8>, HttpError> {
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::http::{Header, Response};
|
||||
use crate::http::{Header, HeaderVec, Response};
|
||||
|
||||
#[test]
|
||||
fn test_parse_content_encoding() {
|
||||
@ -200,8 +197,11 @@ pub mod tests {
|
||||
let response = Response::default();
|
||||
assert_eq!(response.content_encoding().unwrap(), vec![]);
|
||||
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Encoding", "xx"));
|
||||
|
||||
let response = Response {
|
||||
headers: vec![Header::new("Content-Encoding", "xx")],
|
||||
headers,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
@ -211,8 +211,11 @@ pub mod tests {
|
||||
}
|
||||
);
|
||||
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Encoding", "br"));
|
||||
|
||||
let response = Response {
|
||||
headers: vec![Header::new("Content-Encoding", "br")],
|
||||
headers,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
@ -223,8 +226,10 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_multiple_content_encoding() {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Encoding", "br, identity"));
|
||||
let response = Response {
|
||||
headers: vec![Header::new("Content-Encoding", "br, identity")],
|
||||
headers,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
@ -235,8 +240,11 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_uncompress_body() {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Encoding", "br"));
|
||||
|
||||
let response = Response {
|
||||
headers: vec![Header::new("Content-Encoding", "br")],
|
||||
headers,
|
||||
body: vec![
|
||||
0x21, 0x2c, 0x00, 0x04, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x21, 0x03,
|
||||
@ -245,8 +253,10 @@ pub mod tests {
|
||||
};
|
||||
assert_eq!(response.uncompress_body().unwrap(), b"Hello World!");
|
||||
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Encoding", "br, identity"));
|
||||
let response = Response {
|
||||
headers: vec![Header::new("Content-Encoding", "br, identity")],
|
||||
headers,
|
||||
body: vec![
|
||||
0x21, 0x2c, 0x00, 0x04, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x21, 0x03,
|
||||
@ -315,19 +325,25 @@ pub mod tests {
|
||||
}
|
||||
|
||||
fn utf8_encoding_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "text/plain; charset=utf-8"));
|
||||
|
||||
Response {
|
||||
headers: vec![Header::new("Content-Type", "text/plain; charset=utf-8")],
|
||||
headers,
|
||||
body: vec![0x63, 0x61, 0x66, 0xc3, 0xa9],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn latin1_encoding_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new(
|
||||
"Content-Type",
|
||||
"text/plain; charset=ISO-8859-1",
|
||||
));
|
||||
|
||||
Response {
|
||||
headers: vec![Header::new(
|
||||
"Content-Type",
|
||||
"text/plain; charset=ISO-8859-1",
|
||||
)],
|
||||
headers,
|
||||
body: vec![0x63, 0x61, 0x66, 0xe9],
|
||||
..Default::default()
|
||||
}
|
||||
@ -338,11 +354,11 @@ pub mod tests {
|
||||
assert_eq!(hello_response().content_type(), None);
|
||||
assert_eq!(
|
||||
utf8_encoding_response().content_type(),
|
||||
Some("text/plain; charset=utf-8".to_string())
|
||||
Some("text/plain; charset=utf-8")
|
||||
);
|
||||
assert_eq!(
|
||||
latin1_encoding_response().content_type(),
|
||||
Some("text/plain; charset=ISO-8859-1".to_string())
|
||||
Some("text/plain; charset=ISO-8859-1")
|
||||
);
|
||||
}
|
||||
|
||||
@ -380,9 +396,12 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
pub fn test_invalid_charset() {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "test/plain; charset=xxx"));
|
||||
|
||||
assert_eq!(
|
||||
Response {
|
||||
headers: vec![Header::new("Content-Type", "test/plain; charset=xxx"),],
|
||||
headers,
|
||||
body: b"Hello World!".to_vec(),
|
||||
..Default::default()
|
||||
}
|
||||
@ -410,12 +429,15 @@ pub mod tests {
|
||||
}
|
||||
);
|
||||
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new(
|
||||
"Content-Type",
|
||||
"text/plain; charset=ISO-8859-1",
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Response {
|
||||
headers: vec![Header::new(
|
||||
"Content-Type",
|
||||
"text/plain; charset=ISO-8859-1"
|
||||
),],
|
||||
headers,
|
||||
body: vec![0x63, 0x61, 0x66, 0xc3, 0xa9],
|
||||
..Default::default()
|
||||
}
|
||||
|
@ -47,11 +47,12 @@ pub fn json_http_response() -> Response {
|
||||
}
|
||||
|
||||
pub fn xml_two_users_http_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "text/html; charset=utf-8"));
|
||||
headers.push(Header::new("Content-Length", "12"));
|
||||
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
headers,
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
<?xml version="1.0"?>
|
||||
@ -67,11 +68,12 @@ pub fn xml_two_users_http_response() -> Response {
|
||||
}
|
||||
|
||||
pub fn xml_three_users_http_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "text/html; charset=utf-8"));
|
||||
headers.push(Header::new("Content-Length", "12"));
|
||||
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
headers,
|
||||
body: String::into_bytes(
|
||||
r#"
|
||||
<?xml version="1.0"?>
|
||||
@ -88,30 +90,35 @@ pub fn xml_three_users_http_response() -> Response {
|
||||
}
|
||||
|
||||
pub fn hello_http_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "text/html; charset=utf-8"));
|
||||
headers.push(Header::new("Content-Length", "12"));
|
||||
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "text/html; charset=utf-8"),
|
||||
Header::new("Content-Length", "12"),
|
||||
],
|
||||
headers,
|
||||
body: String::into_bytes(String::from("Hello World!")),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_http_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "application/octet-stream"));
|
||||
headers.push(Header::new("Content-Length", "1"));
|
||||
|
||||
Response {
|
||||
headers: vec![
|
||||
Header::new("Content-Type", "application/octet-stream"),
|
||||
Header::new("Content-Length", "1"),
|
||||
],
|
||||
headers,
|
||||
body: vec![255],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn html_http_response() -> Response {
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(Header::new("Content-Type", "application/octet-stream"));
|
||||
|
||||
Response {
|
||||
headers: vec![Header::new("Content-Type", "text/html; charset=utf-8")],
|
||||
headers,
|
||||
body: String::into_bytes(String::from(
|
||||
"<html><head><meta charset=\"UTF-8\"></head><body><br></body></html>",
|
||||
)),
|
||||
|
@ -313,6 +313,7 @@ impl Value {
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::http::HeaderVec;
|
||||
use hex_literal::hex;
|
||||
use hurl_core::ast::{Pos, SourceInfo};
|
||||
|
||||
@ -600,10 +601,11 @@ pub mod tests {
|
||||
value: String::new(),
|
||||
source_info: SourceInfo::new(Pos::new(0, 0), Pos::new(0, 0)),
|
||||
};
|
||||
let mut headers = HeaderVec::new();
|
||||
headers.push(http::Header::new("Set-Cookie", "LSID=DQAAAKEaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly"));
|
||||
|
||||
let response = http::Response {
|
||||
headers: vec![
|
||||
http::Header::new("Set-Cookie", "LSID=DQAAAKEaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly")
|
||||
],
|
||||
headers,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -112,12 +112,12 @@ pub fn eval_asserts(
|
||||
actuals
|
||||
.iter()
|
||||
.map(|v| format!("\"{v}\""))
|
||||
.collect::<Vec<String>>()
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
for value in actuals {
|
||||
if value == expected {
|
||||
actual = value;
|
||||
actual = value.to_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user