headers_ext/common/
authorization.rs1use base64;
4use bytes::Bytes;
5
6use {HeaderValue};
7use util::HeaderValueString;
8
9#[derive(Clone, PartialEq, Debug)]
38pub struct Authorization<C: Credentials>(pub C);
39
40impl Authorization<Basic> {
41 pub fn basic(username: &str, password: &str) -> Self {
43 let colon_pos = username.len();
44 let decoded = format!("{}:{}", username, password);
45
46 Authorization(Basic {
47 decoded,
48 colon_pos,
49 })
50 }
51}
52
53impl Authorization<Bearer> {
54 pub fn bearer(token: &str) -> Result<Self, InvalidBearerToken> {
56 HeaderValueString::from_string(format!("Bearer {}", token))
57 .map(|val| Authorization(Bearer(val)))
58 .ok_or_else(|| InvalidBearerToken { _inner: () })
59 }
60}
61
62impl<C: Credentials> ::Header for Authorization<C> {
63 const NAME: &'static ::HeaderName = &::http::header::AUTHORIZATION;
64
65 fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
66 values
67 .next()
68 .and_then(|val| {
69 let slice = val.as_bytes();
70 if slice.starts_with(C::SCHEME.as_bytes())
71 && slice.len() > C::SCHEME.len()
72 && slice[C::SCHEME.len()] == b' ' {
73 C::decode(val)
74 .map(Authorization)
75 } else {
76 None
77 }
78 })
79 .ok_or_else(::Error::invalid)
80 }
81
82 fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
83 let value = self.0.encode();
84 debug_assert!(
85 value.as_bytes().starts_with(C::SCHEME.as_bytes()),
86 "Credentials::encode should include its scheme: scheme = {:?}, encoded = {:?}",
87 C::SCHEME,
88 value,
89 );
90
91 values.extend(::std::iter::once(value));
92 }
93}
94
95pub trait Credentials: Sized {
97 const SCHEME: &'static str;
102
103 fn decode(value: &HeaderValue) -> Option<Self>;
107
108 fn encode(&self) -> HeaderValue;
112}
113
114#[derive(Clone, PartialEq, Debug)]
116pub struct Basic {
117 decoded: String,
118 colon_pos: usize,
119}
120
121impl Basic {
122 pub fn username(&self) -> &str {
124 &self.decoded[..self.colon_pos]
125 }
126
127 pub fn password(&self) -> &str {
129 &self.decoded[self.colon_pos + 1..]
130 }
131}
132
133impl Credentials for Basic {
134 const SCHEME: &'static str = "Basic";
135
136 fn decode(value: &HeaderValue) -> Option<Self> {
137 debug_assert!(
138 value.as_bytes().starts_with(b"Basic "),
139 "HeaderValue to decode should start with \"Basic ..\", received = {:?}",
140 value,
141 );
142
143 let bytes = base64::decode(&value.as_bytes()["Basic ".len()..]).ok()?;
144 let decoded = String::from_utf8(bytes).ok()?;
145
146 let colon_pos = decoded.find(':')?;
147
148 Some(Basic {
149 decoded,
150 colon_pos,
151 })
152 }
153
154 fn encode(&self) -> HeaderValue {
155 let mut encoded = String::from("Basic ");
156 base64::encode_config_buf(&self.decoded, base64::STANDARD, &mut encoded);
157
158 let bytes = Bytes::from(encoded);
159 HeaderValue::from_shared(bytes)
160 .expect("base64 encoding is always a valid HeaderValue")
161 }
162}
163
164#[derive(Clone, PartialEq, Debug)]
165pub struct Bearer(HeaderValueString);
167
168impl Bearer {
169 pub fn token(&self) -> &str {
171 &self.0.as_str()["Bearer ".len() ..]
172 }
173}
174
175impl Credentials for Bearer {
176 const SCHEME: &'static str = "Bearer";
177
178 fn decode(value: &HeaderValue) -> Option<Self> {
179 debug_assert!(
180 value.as_bytes().starts_with(b"Bearer "),
181 "HeaderValue to decode should start with \"Bearer ..\", received = {:?}",
182 value,
183 );
184
185 HeaderValueString::from_val(value)
186 .ok()
187 .map(Bearer)
188 }
189
190 fn encode(&self) -> HeaderValue {
191 (&self.0).into()
192 }
193}
194
195error_type!(InvalidBearerToken);
196
197
198#[cfg(test)]
199mod tests {
200 use headers_core::HeaderMapExt;
201 use http::header::HeaderMap;
202 use super::{Authorization, Basic, Bearer};
203 use super::super::{test_decode, test_encode};
204
205 #[test]
206 fn basic_encode() {
207 let auth = Authorization::basic("Aladdin", "open sesame");
208 let headers = test_encode(auth);
209
210 assert_eq!(
211 headers["authorization"],
212 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
213 );
214 }
215
216 #[test]
217 fn basic_roundtrip() {
218 let auth = Authorization::basic("Aladdin", "open sesame");
219 let mut h = HeaderMap::new();
220 h.typed_insert(auth.clone());
221 assert_eq!(h.typed_get(), Some(auth));
222 }
223
224 #[test]
225 fn basic_encode_no_password() {
226 let auth = Authorization::basic("Aladdin", "");
227 let headers = test_encode(auth);
228
229 assert_eq!(
230 headers["authorization"],
231 "Basic QWxhZGRpbjo=",
232 );
233 }
234
235 #[test]
236 fn basic_decode() {
237 let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
238 assert_eq!(auth.0.username(), "Aladdin");
239 assert_eq!(auth.0.password(), "open sesame");
240 }
241
242 #[test]
243 fn basic_decode_no_password() {
244 let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjo="]).unwrap();
245 assert_eq!(auth.0.username(), "Aladdin");
246 assert_eq!(auth.0.password(), "");
247 }
248
249 #[test]
250 fn bearer_encode() {
251 let auth = Authorization::bearer("fpKL54jvWmEGVoRdCNjG").unwrap();
252
253 let headers = test_encode(auth);
254
255 assert_eq!(
256 headers["authorization"],
257 "Bearer fpKL54jvWmEGVoRdCNjG",
258 );
259 }
260
261 #[test]
262 fn bearer_decode() {
263 let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
264 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
265 }
266}
267
268