Skip to content

Commit bcdcb2a

Browse files
committed
Use HeaderMap for headers in mock and response
1 parent b9007ea commit bcdcb2a

6 files changed

Lines changed: 31 additions & 27 deletions

File tree

src/matcher.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use assert_json_diff::{assert_json_matches_no_panic, CompareMode};
2+
use hyper::header::HeaderValue;
23
use regex::Regex;
34
use std::collections::HashMap;
45
use std::convert::From;
@@ -108,7 +109,7 @@ impl fmt::Display for Matcher {
108109
}
109110

110111
impl Matcher {
111-
pub(crate) fn matches_values(&self, header_values: &[&str]) -> bool {
112+
pub(crate) fn matches_values(&self, header_values: &[&HeaderValue]) -> bool {
112113
match self {
113114
Matcher::Missing => header_values.is_empty(),
114115
// AnyOf([…Missing…]) is handled here, but
@@ -122,7 +123,12 @@ impl Matcher {
122123
matchers.iter().all(|m| m.matches_values(header_values))
123124
}
124125
_ => {
125-
!header_values.is_empty() && header_values.iter().all(|val| self.matches_value(val))
126+
!header_values.is_empty()
127+
&& header_values.iter().all(|val| {
128+
val.to_str()
129+
.map(|val| self.matches_value(val))
130+
.unwrap_or(false)
131+
})
126132
}
127133
}
128134
}

src/mock.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use crate::server::RemoteMock;
55
use crate::server::State;
66
use crate::Request;
77
use crate::{Error, ErrorKind};
8+
use hyper::header::IntoHeaderName;
9+
use hyper::HeaderMap;
810
use hyper::StatusCode;
911
use rand::distributions::Alphanumeric;
1012
use rand::{thread_rng, Rng};
@@ -22,7 +24,7 @@ pub struct InnerMock {
2224
pub(crate) id: String,
2325
pub(crate) method: String,
2426
pub(crate) path: PathAndQueryMatcher,
25-
pub(crate) headers: Vec<(String, Matcher)>,
27+
pub(crate) headers: HeaderMap<Matcher>,
2628
pub(crate) body: Matcher,
2729
pub(crate) response: Response,
2830
pub(crate) hits: usize,
@@ -40,8 +42,8 @@ impl fmt::Display for InnerMock {
4042
formatted.push(' ');
4143
formatted.push_str(&self.path.to_string());
4244

43-
for &(ref key, ref value) in &self.headers {
44-
formatted.push_str(key);
45+
for (key, value) in &self.headers {
46+
formatted.push_str(key.as_str());
4547
formatted.push_str(": ");
4648
formatted.push_str(&value.to_string());
4749
formatted.push_str("\r\n");
@@ -110,7 +112,7 @@ impl Mock {
110112
.collect(),
111113
method: method.to_owned().to_uppercase(),
112114
path: PathAndQueryMatcher::Unified(path.into()),
113-
headers: Vec::new(),
115+
headers: HeaderMap::<Matcher>::default(),
114116
body: Matcher::Any,
115117
response: Response::default(),
116118
hits: 0,
@@ -200,10 +202,8 @@ impl Mock {
200202
/// .match_header("authorization", "password");
201203
/// ```
202204
///
203-
pub fn match_header<M: Into<Matcher>>(mut self, field: &str, value: M) -> Self {
204-
self.inner
205-
.headers
206-
.push((field.to_owned().to_lowercase(), value.into()));
205+
pub fn match_header<T: IntoHeaderName, M: Into<Matcher>>(mut self, field: T, value: M) -> Self {
206+
self.inner.headers.append(field, value.into());
207207

208208
self
209209
}
@@ -283,11 +283,8 @@ impl Mock {
283283
/// s.mock("GET", "/").with_header("content-type", "application/json");
284284
/// ```
285285
///
286-
pub fn with_header(mut self, field: &str, value: &str) -> Self {
287-
self.inner
288-
.response
289-
.headers
290-
.push((field.to_owned(), value.to_owned()));
286+
pub fn with_header<T: IntoHeaderName>(mut self, field: T, value: &str) -> Self {
287+
self.inner.response.headers.append(field, value.to_owned());
291288

292289
self
293290
}

src/request.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::{Error, ErrorKind};
22
use hyper::body;
33
use hyper::body::Buf;
4+
use hyper::header::AsHeaderName;
5+
use hyper::header::HeaderValue;
46
use hyper::Body as HyperBody;
57
use hyper::Request as HyperRequest;
68

@@ -41,17 +43,12 @@ impl Request {
4143
}
4244

4345
/// Retrieves all the header values for the given header field name
44-
pub fn header(&self, header_name: &str) -> Vec<&str> {
45-
self.inner
46-
.headers()
47-
.get_all(header_name)
48-
.iter()
49-
.map(|item| item.to_str().unwrap())
50-
.collect::<Vec<&str>>()
46+
pub fn header<T: AsHeaderName>(&self, header_name: T) -> Vec<&HeaderValue> {
47+
self.inner.headers().get_all(header_name).iter().collect()
5148
}
5249

5350
/// Checks whether the provided header field exists
54-
pub fn has_header(&self, header_name: &str) -> bool {
51+
pub fn has_header<T: AsHeaderName>(&self, header_name: T) -> bool {
5552
self.inner.headers().contains_key(header_name)
5653
}
5754

src/response.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::error::Error;
22
use crate::Request;
33
use futures::stream::Stream;
4+
use hyper::HeaderMap;
45
use hyper::StatusCode;
56
use std::fmt;
67
use std::io;
@@ -12,7 +13,7 @@ use tokio::sync::mpsc;
1213
#[derive(Clone, Debug, PartialEq)]
1314
pub(crate) struct Response {
1415
pub status: StatusCode,
15-
pub headers: Vec<(String, String)>,
16+
pub headers: HeaderMap<String>,
1617
pub body: Body,
1718
}
1819

@@ -55,9 +56,11 @@ impl PartialEq for Body {
5556

5657
impl Default for Response {
5758
fn default() -> Self {
59+
let mut headers = HeaderMap::with_capacity(1);
60+
headers.insert("connection", "close".parse().unwrap());
5861
Self {
5962
status: StatusCode::OK,
60-
headers: vec![("connection".into(), "close".into())],
63+
headers,
6164
body: Body::Bytes(Vec::new()),
6265
}
6366
}

src/server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl RemoteMock {
4444
self.inner
4545
.headers
4646
.iter()
47-
.all(|&(ref field, ref expected)| expected.matches_values(&request.header(field)))
47+
.all(|(field, expected)| expected.matches_values(&request.header(field)))
4848
}
4949

5050
fn body_matches(&self, request: &mut Request) -> bool {

tests/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[macro_use]
22
extern crate serde_json;
33

4+
use hyper::header::HeaderName;
45
use mockito::{Matcher, Server};
56
use rand::distributions::Alphanumeric;
67
use rand::Rng;
@@ -699,7 +700,7 @@ fn test_mock_preserves_header_order() {
699700

700701
// Add a large number of headers so getting the same order accidentally is unlikely.
701702
for i in 0..100 {
702-
let field = format!("x-custom-header-{}", i);
703+
let field: HeaderName = format!("x-custom-header-{}", i).try_into().unwrap();
703704
let value = "test";
704705
mock = mock.with_header(&field, value);
705706
expected_headers.push(format!("{}: {}", field, value));

0 commit comments

Comments
 (0)