1 | use bytes::{Bytes, BytesMut}; |
2 | |
3 | use std::convert::TryFrom; |
4 | use std::error::Error; |
5 | use std::fmt::Write; |
6 | use std::str::FromStr; |
7 | use std::{cmp, fmt, mem, str}; |
8 | |
9 | use crate::header::name::HeaderName; |
10 | |
11 | /// Represents an HTTP header field value. |
12 | /// |
13 | /// In practice, HTTP header field values are usually valid ASCII. However, the |
14 | /// HTTP spec allows for a header value to contain opaque bytes as well. In this |
15 | /// case, the header field value is not able to be represented as a string. |
16 | /// |
17 | /// To handle this, the `HeaderValue` is useable as a type and can be compared |
18 | /// with strings and implements `Debug`. A `to_str` fn is provided that returns |
19 | /// an `Err` if the header value contains non visible ascii characters. |
20 | #[derive(Clone, Hash)] |
21 | pub struct HeaderValue { |
22 | inner: Bytes, |
23 | is_sensitive: bool, |
24 | } |
25 | |
26 | /// A possible error when converting a `HeaderValue` from a string or byte |
27 | /// slice. |
28 | pub struct InvalidHeaderValue { |
29 | _priv: (), |
30 | } |
31 | |
32 | /// A possible error when converting a `HeaderValue` to a string representation. |
33 | /// |
34 | /// Header field values may contain opaque bytes, in which case it is not |
35 | /// possible to represent the value as a string. |
36 | #[derive(Debug)] |
37 | pub struct ToStrError { |
38 | _priv: (), |
39 | } |
40 | |
41 | impl HeaderValue { |
42 | /// Convert a static string to a `HeaderValue`. |
43 | /// |
44 | /// This function will not perform any copying, however the string is |
45 | /// checked to ensure that no invalid characters are present. Only visible |
46 | /// ASCII characters (32-127) are permitted. |
47 | /// |
48 | /// # Panics |
49 | /// |
50 | /// This function panics if the argument contains invalid header value |
51 | /// characters. |
52 | /// |
53 | /// Until [Allow panicking in constants](https://github.com/rust-lang/rfcs/pull/2345) |
54 | /// makes its way into stable, the panic message at compile-time is |
55 | /// going to look cryptic, but should at least point at your header value: |
56 | /// |
57 | /// ```text |
58 | /// error: any use of this value will cause an error |
59 | /// --> http/src/header/value.rs:67:17 |
60 | /// | |
61 | /// 67 | ([] as [u8; 0])[0]; // Invalid header value |
62 | /// | ^^^^^^^^^^^^^^^^^^ |
63 | /// | | |
64 | /// | index out of bounds: the length is 0 but the index is 0 |
65 | /// | inside `HeaderValue::from_static` at http/src/header/value.rs:67:17 |
66 | /// | inside `INVALID_HEADER` at src/main.rs:73:33 |
67 | /// | |
68 | /// ::: src/main.rs:73:1 |
69 | /// | |
70 | /// 73 | const INVALID_HEADER: HeaderValue = HeaderValue::from_static("жsome value"); |
71 | /// | ---------------------------------------------------------------------------- |
72 | /// ``` |
73 | /// |
74 | /// # Examples |
75 | /// |
76 | /// ``` |
77 | /// # use http::header::HeaderValue; |
78 | /// let val = HeaderValue::from_static("hello" ); |
79 | /// assert_eq!(val, "hello" ); |
80 | /// ``` |
81 | #[inline ] |
82 | #[allow (unconditional_panic)] // required for the panic circumvention |
83 | pub const fn from_static(src: &'static str) -> HeaderValue { |
84 | let bytes = src.as_bytes(); |
85 | let mut i = 0; |
86 | while i < bytes.len() { |
87 | if !is_visible_ascii(bytes[i]) { |
88 | ([] as [u8; 0])[0]; // Invalid header value |
89 | } |
90 | i += 1; |
91 | } |
92 | |
93 | HeaderValue { |
94 | inner: Bytes::from_static(bytes), |
95 | is_sensitive: false, |
96 | } |
97 | } |
98 | |
99 | /// Attempt to convert a string to a `HeaderValue`. |
100 | /// |
101 | /// If the argument contains invalid header value characters, an error is |
102 | /// returned. Only visible ASCII characters (32-127) are permitted. Use |
103 | /// `from_bytes` to create a `HeaderValue` that includes opaque octets |
104 | /// (128-255). |
105 | /// |
106 | /// This function is intended to be replaced in the future by a `TryFrom` |
107 | /// implementation once the trait is stabilized in std. |
108 | /// |
109 | /// # Examples |
110 | /// |
111 | /// ``` |
112 | /// # use http::header::HeaderValue; |
113 | /// let val = HeaderValue::from_str("hello" ).unwrap(); |
114 | /// assert_eq!(val, "hello" ); |
115 | /// ``` |
116 | /// |
117 | /// An invalid value |
118 | /// |
119 | /// ``` |
120 | /// # use http::header::HeaderValue; |
121 | /// let val = HeaderValue::from_str(" \n" ); |
122 | /// assert!(val.is_err()); |
123 | /// ``` |
124 | #[inline ] |
125 | pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> { |
126 | HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes())) |
127 | } |
128 | |
129 | /// Converts a HeaderName into a HeaderValue |
130 | /// |
131 | /// Since every valid HeaderName is a valid HeaderValue this is done infallibly. |
132 | /// |
133 | /// # Examples |
134 | /// |
135 | /// ``` |
136 | /// # use http::header::{HeaderValue, HeaderName}; |
137 | /// # use http::header::ACCEPT; |
138 | /// let val = HeaderValue::from_name(ACCEPT); |
139 | /// assert_eq!(val, HeaderValue::from_bytes(b"accept" ).unwrap()); |
140 | /// ``` |
141 | #[inline ] |
142 | pub fn from_name(name: HeaderName) -> HeaderValue { |
143 | name.into() |
144 | } |
145 | |
146 | /// Attempt to convert a byte slice to a `HeaderValue`. |
147 | /// |
148 | /// If the argument contains invalid header value bytes, an error is |
149 | /// returned. Only byte values between 32 and 255 (inclusive) are permitted, |
150 | /// excluding byte 127 (DEL). |
151 | /// |
152 | /// This function is intended to be replaced in the future by a `TryFrom` |
153 | /// implementation once the trait is stabilized in std. |
154 | /// |
155 | /// # Examples |
156 | /// |
157 | /// ``` |
158 | /// # use http::header::HeaderValue; |
159 | /// let val = HeaderValue::from_bytes(b"hello \xfa" ).unwrap(); |
160 | /// assert_eq!(val, &b"hello \xfa" [..]); |
161 | /// ``` |
162 | /// |
163 | /// An invalid value |
164 | /// |
165 | /// ``` |
166 | /// # use http::header::HeaderValue; |
167 | /// let val = HeaderValue::from_bytes(b" \n" ); |
168 | /// assert!(val.is_err()); |
169 | /// ``` |
170 | #[inline ] |
171 | pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> { |
172 | HeaderValue::try_from_generic(src, Bytes::copy_from_slice) |
173 | } |
174 | |
175 | /// Attempt to convert a `Bytes` buffer to a `HeaderValue`. |
176 | /// |
177 | /// This will try to prevent a copy if the type passed is the type used |
178 | /// internally, and will copy the data if it is not. |
179 | pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue> |
180 | where |
181 | T: AsRef<[u8]> + 'static, |
182 | { |
183 | if_downcast_into!(T, Bytes, src, { |
184 | return HeaderValue::from_shared(src); |
185 | }); |
186 | |
187 | HeaderValue::from_bytes(src.as_ref()) |
188 | } |
189 | |
190 | /// Convert a `Bytes` directly into a `HeaderValue` without validating. |
191 | /// |
192 | /// This function does NOT validate that illegal bytes are not contained |
193 | /// within the buffer. |
194 | pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue |
195 | where |
196 | T: AsRef<[u8]> + 'static, |
197 | { |
198 | if cfg!(debug_assertions) { |
199 | match HeaderValue::from_maybe_shared(src) { |
200 | Ok(val) => val, |
201 | Err(_err) => { |
202 | panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes" ); |
203 | } |
204 | } |
205 | } else { |
206 | |
207 | if_downcast_into!(T, Bytes, src, { |
208 | return HeaderValue { |
209 | inner: src, |
210 | is_sensitive: false, |
211 | }; |
212 | }); |
213 | |
214 | let src = Bytes::copy_from_slice(src.as_ref()); |
215 | HeaderValue { |
216 | inner: src, |
217 | is_sensitive: false, |
218 | } |
219 | } |
220 | } |
221 | |
222 | fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> { |
223 | HeaderValue::try_from_generic(src, std::convert::identity) |
224 | } |
225 | |
226 | fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(src: T, into: F) -> Result<HeaderValue, InvalidHeaderValue> { |
227 | for &b in src.as_ref() { |
228 | if !is_valid(b) { |
229 | return Err(InvalidHeaderValue { _priv: () }); |
230 | } |
231 | } |
232 | Ok(HeaderValue { |
233 | inner: into(src), |
234 | is_sensitive: false, |
235 | }) |
236 | } |
237 | |
238 | /// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII |
239 | /// chars. |
240 | /// |
241 | /// This function will perform a scan of the header value, checking all the |
242 | /// characters. |
243 | /// |
244 | /// # Examples |
245 | /// |
246 | /// ``` |
247 | /// # use http::header::HeaderValue; |
248 | /// let val = HeaderValue::from_static("hello" ); |
249 | /// assert_eq!(val.to_str().unwrap(), "hello" ); |
250 | /// ``` |
251 | pub fn to_str(&self) -> Result<&str, ToStrError> { |
252 | let bytes = self.as_ref(); |
253 | |
254 | for &b in bytes { |
255 | if !is_visible_ascii(b) { |
256 | return Err(ToStrError { _priv: () }); |
257 | } |
258 | } |
259 | |
260 | unsafe { Ok(str::from_utf8_unchecked(bytes)) } |
261 | } |
262 | |
263 | /// Returns the length of `self`. |
264 | /// |
265 | /// This length is in bytes. |
266 | /// |
267 | /// # Examples |
268 | /// |
269 | /// ``` |
270 | /// # use http::header::HeaderValue; |
271 | /// let val = HeaderValue::from_static("hello" ); |
272 | /// assert_eq!(val.len(), 5); |
273 | /// ``` |
274 | #[inline ] |
275 | pub fn len(&self) -> usize { |
276 | self.as_ref().len() |
277 | } |
278 | |
279 | /// Returns true if the `HeaderValue` has a length of zero bytes. |
280 | /// |
281 | /// # Examples |
282 | /// |
283 | /// ``` |
284 | /// # use http::header::HeaderValue; |
285 | /// let val = HeaderValue::from_static("" ); |
286 | /// assert!(val.is_empty()); |
287 | /// |
288 | /// let val = HeaderValue::from_static("hello" ); |
289 | /// assert!(!val.is_empty()); |
290 | /// ``` |
291 | #[inline ] |
292 | pub fn is_empty(&self) -> bool { |
293 | self.len() == 0 |
294 | } |
295 | |
296 | /// Converts a `HeaderValue` to a byte slice. |
297 | /// |
298 | /// # Examples |
299 | /// |
300 | /// ``` |
301 | /// # use http::header::HeaderValue; |
302 | /// let val = HeaderValue::from_static("hello" ); |
303 | /// assert_eq!(val.as_bytes(), b"hello" ); |
304 | /// ``` |
305 | #[inline ] |
306 | pub fn as_bytes(&self) -> &[u8] { |
307 | self.as_ref() |
308 | } |
309 | |
310 | /// Mark that the header value represents sensitive information. |
311 | /// |
312 | /// # Examples |
313 | /// |
314 | /// ``` |
315 | /// # use http::header::HeaderValue; |
316 | /// let mut val = HeaderValue::from_static("my secret" ); |
317 | /// |
318 | /// val.set_sensitive(true); |
319 | /// assert!(val.is_sensitive()); |
320 | /// |
321 | /// val.set_sensitive(false); |
322 | /// assert!(!val.is_sensitive()); |
323 | /// ``` |
324 | #[inline ] |
325 | pub fn set_sensitive(&mut self, val: bool) { |
326 | self.is_sensitive = val; |
327 | } |
328 | |
329 | /// Returns `true` if the value represents sensitive data. |
330 | /// |
331 | /// Sensitive data could represent passwords or other data that should not |
332 | /// be stored on disk or in memory. By marking header values as sensitive, |
333 | /// components using this crate can be instructed to treat them with special |
334 | /// care for security reasons. For example, caches can avoid storing |
335 | /// sensitive values, and HPACK encoders used by HTTP/2.0 implementations |
336 | /// can choose not to compress them. |
337 | /// |
338 | /// Additionally, sensitive values will be masked by the `Debug` |
339 | /// implementation of `HeaderValue`. |
340 | /// |
341 | /// Note that sensitivity is not factored into equality or ordering. |
342 | /// |
343 | /// # Examples |
344 | /// |
345 | /// ``` |
346 | /// # use http::header::HeaderValue; |
347 | /// let mut val = HeaderValue::from_static("my secret" ); |
348 | /// |
349 | /// val.set_sensitive(true); |
350 | /// assert!(val.is_sensitive()); |
351 | /// |
352 | /// val.set_sensitive(false); |
353 | /// assert!(!val.is_sensitive()); |
354 | /// ``` |
355 | #[inline ] |
356 | pub fn is_sensitive(&self) -> bool { |
357 | self.is_sensitive |
358 | } |
359 | } |
360 | |
361 | impl AsRef<[u8]> for HeaderValue { |
362 | #[inline ] |
363 | fn as_ref(&self) -> &[u8] { |
364 | self.inner.as_ref() |
365 | } |
366 | } |
367 | |
368 | impl fmt::Debug for HeaderValue { |
369 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
370 | if self.is_sensitive { |
371 | f.write_str("Sensitive" ) |
372 | } else { |
373 | f.write_str(" \"" )?; |
374 | let mut from = 0; |
375 | let bytes = self.as_bytes(); |
376 | for (i, &b) in bytes.iter().enumerate() { |
377 | if !is_visible_ascii(b) || b == b'"' { |
378 | if from != i { |
379 | f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?; |
380 | } |
381 | if b == b'"' { |
382 | f.write_str(" \\\"" )?; |
383 | } else { |
384 | write!(f, " \\x{:x}" , b)?; |
385 | } |
386 | from = i + 1; |
387 | } |
388 | } |
389 | |
390 | f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?; |
391 | f.write_str(" \"" ) |
392 | } |
393 | } |
394 | } |
395 | |
396 | impl From<HeaderName> for HeaderValue { |
397 | #[inline ] |
398 | fn from(h: HeaderName) -> HeaderValue { |
399 | HeaderValue { |
400 | inner: h.into_bytes(), |
401 | is_sensitive: false, |
402 | } |
403 | } |
404 | } |
405 | |
406 | macro_rules! from_integers { |
407 | ($($name:ident: $t:ident => $max_len:expr),*) => {$( |
408 | impl From<$t> for HeaderValue { |
409 | fn from(num: $t) -> HeaderValue { |
410 | let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len { |
411 | // On 32bit platforms, BytesMut max inline size |
412 | // is 15 bytes, but the $max_len could be bigger. |
413 | // |
414 | // The likelihood of the number *actually* being |
415 | // that big is very small, so only allocate |
416 | // if the number needs that space. |
417 | // |
418 | // The largest decimal number in 15 digits: |
419 | // It wold be 10.pow(15) - 1, but this is a constant |
420 | // version. |
421 | if num as u64 > 999_999_999_999_999_999 { |
422 | BytesMut::with_capacity($max_len) |
423 | } else { |
424 | // fits inline... |
425 | BytesMut::new() |
426 | } |
427 | } else { |
428 | // full value fits inline, so don't allocate! |
429 | BytesMut::new() |
430 | }; |
431 | let _ = buf.write_str(::itoa::Buffer::new().format(num)); |
432 | HeaderValue { |
433 | inner: buf.freeze(), |
434 | is_sensitive: false, |
435 | } |
436 | } |
437 | } |
438 | |
439 | #[test] |
440 | fn $name() { |
441 | let n: $t = 55; |
442 | let val = HeaderValue::from(n); |
443 | assert_eq!(val, &n.to_string()); |
444 | |
445 | let n = ::std::$t::MAX; |
446 | let val = HeaderValue::from(n); |
447 | assert_eq!(val, &n.to_string()); |
448 | } |
449 | )*}; |
450 | } |
451 | |
452 | from_integers! { |
453 | // integer type => maximum decimal length |
454 | |
455 | // u8 purposely left off... HeaderValue::from(b'3') could be confusing |
456 | from_u16: u16 => 5, |
457 | from_i16: i16 => 6, |
458 | from_u32: u32 => 10, |
459 | from_i32: i32 => 11, |
460 | from_u64: u64 => 20, |
461 | from_i64: i64 => 20 |
462 | } |
463 | |
464 | #[cfg (target_pointer_width = "16" )] |
465 | from_integers! { |
466 | from_usize: usize => 5, |
467 | from_isize: isize => 6 |
468 | } |
469 | |
470 | #[cfg (target_pointer_width = "32" )] |
471 | from_integers! { |
472 | from_usize: usize => 10, |
473 | from_isize: isize => 11 |
474 | } |
475 | |
476 | #[cfg (target_pointer_width = "64" )] |
477 | from_integers! { |
478 | from_usize: usize => 20, |
479 | from_isize: isize => 20 |
480 | } |
481 | |
482 | #[cfg (test)] |
483 | mod from_header_name_tests { |
484 | use super::*; |
485 | use crate::header::map::HeaderMap; |
486 | use crate::header::name; |
487 | |
488 | #[test] |
489 | fn it_can_insert_header_name_as_header_value() { |
490 | let mut map = HeaderMap::new(); |
491 | map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into()); |
492 | map.insert( |
493 | name::ACCEPT, |
494 | name::HeaderName::from_bytes(b"hello-world" ).unwrap().into(), |
495 | ); |
496 | |
497 | assert_eq!( |
498 | map.get(name::UPGRADE).unwrap(), |
499 | HeaderValue::from_bytes(b"sec-websocket-protocol" ).unwrap() |
500 | ); |
501 | |
502 | assert_eq!( |
503 | map.get(name::ACCEPT).unwrap(), |
504 | HeaderValue::from_bytes(b"hello-world" ).unwrap() |
505 | ); |
506 | } |
507 | } |
508 | |
509 | impl FromStr for HeaderValue { |
510 | type Err = InvalidHeaderValue; |
511 | |
512 | #[inline ] |
513 | fn from_str(s: &str) -> Result<HeaderValue, Self::Err> { |
514 | HeaderValue::from_str(s) |
515 | } |
516 | } |
517 | |
518 | impl<'a> From<&'a HeaderValue> for HeaderValue { |
519 | #[inline ] |
520 | fn from(t: &'a HeaderValue) -> Self { |
521 | t.clone() |
522 | } |
523 | } |
524 | |
525 | impl<'a> TryFrom<&'a str> for HeaderValue { |
526 | type Error = InvalidHeaderValue; |
527 | |
528 | #[inline ] |
529 | fn try_from(t: &'a str) -> Result<Self, Self::Error> { |
530 | t.parse() |
531 | } |
532 | } |
533 | |
534 | impl<'a> TryFrom<&'a String> for HeaderValue { |
535 | type Error = InvalidHeaderValue; |
536 | #[inline ] |
537 | fn try_from(s: &'a String) -> Result<Self, Self::Error> { |
538 | Self::from_bytes(s.as_bytes()) |
539 | } |
540 | } |
541 | |
542 | impl<'a> TryFrom<&'a [u8]> for HeaderValue { |
543 | type Error = InvalidHeaderValue; |
544 | |
545 | #[inline ] |
546 | fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> { |
547 | HeaderValue::from_bytes(t) |
548 | } |
549 | } |
550 | |
551 | impl TryFrom<String> for HeaderValue { |
552 | type Error = InvalidHeaderValue; |
553 | |
554 | #[inline ] |
555 | fn try_from(t: String) -> Result<Self, Self::Error> { |
556 | HeaderValue::from_shared(t.into()) |
557 | } |
558 | } |
559 | |
560 | impl TryFrom<Vec<u8>> for HeaderValue { |
561 | type Error = InvalidHeaderValue; |
562 | |
563 | #[inline ] |
564 | fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> { |
565 | HeaderValue::from_shared(vec.into()) |
566 | } |
567 | } |
568 | |
569 | #[cfg (test)] |
570 | mod try_from_header_name_tests { |
571 | use super::*; |
572 | use crate::header::name; |
573 | |
574 | #[test] |
575 | fn it_converts_using_try_from() { |
576 | assert_eq!( |
577 | HeaderValue::try_from(name::UPGRADE).unwrap(), |
578 | HeaderValue::from_bytes(b"upgrade" ).unwrap() |
579 | ); |
580 | } |
581 | } |
582 | |
583 | const fn is_visible_ascii(b: u8) -> bool { |
584 | b >= 32 && b < 127 || b == b' \t' |
585 | } |
586 | |
587 | #[inline ] |
588 | fn is_valid(b: u8) -> bool { |
589 | b >= 32 && b != 127 || b == b' \t' |
590 | } |
591 | |
592 | impl fmt::Debug for InvalidHeaderValue { |
593 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
594 | f.debug_struct("InvalidHeaderValue" ) |
595 | // skip _priv noise |
596 | .finish() |
597 | } |
598 | } |
599 | |
600 | impl fmt::Display for InvalidHeaderValue { |
601 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
602 | f.write_str("failed to parse header value" ) |
603 | } |
604 | } |
605 | |
606 | impl Error for InvalidHeaderValue {} |
607 | |
608 | impl fmt::Display for ToStrError { |
609 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
610 | f.write_str("failed to convert header to a str" ) |
611 | } |
612 | } |
613 | |
614 | impl Error for ToStrError {} |
615 | |
616 | // ===== PartialEq / PartialOrd ===== |
617 | |
618 | impl PartialEq for HeaderValue { |
619 | #[inline ] |
620 | fn eq(&self, other: &HeaderValue) -> bool { |
621 | self.inner == other.inner |
622 | } |
623 | } |
624 | |
625 | impl Eq for HeaderValue {} |
626 | |
627 | impl PartialOrd for HeaderValue { |
628 | #[inline ] |
629 | fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> { |
630 | self.inner.partial_cmp(&other.inner) |
631 | } |
632 | } |
633 | |
634 | impl Ord for HeaderValue { |
635 | #[inline ] |
636 | fn cmp(&self, other: &Self) -> cmp::Ordering { |
637 | self.inner.cmp(&other.inner) |
638 | } |
639 | } |
640 | |
641 | impl PartialEq<str> for HeaderValue { |
642 | #[inline ] |
643 | fn eq(&self, other: &str) -> bool { |
644 | self.inner == other.as_bytes() |
645 | } |
646 | } |
647 | |
648 | impl PartialEq<[u8]> for HeaderValue { |
649 | #[inline ] |
650 | fn eq(&self, other: &[u8]) -> bool { |
651 | self.inner == other |
652 | } |
653 | } |
654 | |
655 | impl PartialOrd<str> for HeaderValue { |
656 | #[inline ] |
657 | fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> { |
658 | (*self.inner).partial_cmp(other.as_bytes()) |
659 | } |
660 | } |
661 | |
662 | impl PartialOrd<[u8]> for HeaderValue { |
663 | #[inline ] |
664 | fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> { |
665 | (*self.inner).partial_cmp(other) |
666 | } |
667 | } |
668 | |
669 | impl PartialEq<HeaderValue> for str { |
670 | #[inline ] |
671 | fn eq(&self, other: &HeaderValue) -> bool { |
672 | *other == *self |
673 | } |
674 | } |
675 | |
676 | impl PartialEq<HeaderValue> for [u8] { |
677 | #[inline ] |
678 | fn eq(&self, other: &HeaderValue) -> bool { |
679 | *other == *self |
680 | } |
681 | } |
682 | |
683 | impl PartialOrd<HeaderValue> for str { |
684 | #[inline ] |
685 | fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> { |
686 | self.as_bytes().partial_cmp(other.as_bytes()) |
687 | } |
688 | } |
689 | |
690 | impl PartialOrd<HeaderValue> for [u8] { |
691 | #[inline ] |
692 | fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> { |
693 | self.partial_cmp(other.as_bytes()) |
694 | } |
695 | } |
696 | |
697 | impl PartialEq<String> for HeaderValue { |
698 | #[inline ] |
699 | fn eq(&self, other: &String) -> bool { |
700 | *self == &other[..] |
701 | } |
702 | } |
703 | |
704 | impl PartialOrd<String> for HeaderValue { |
705 | #[inline ] |
706 | fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> { |
707 | self.inner.partial_cmp(other.as_bytes()) |
708 | } |
709 | } |
710 | |
711 | impl PartialEq<HeaderValue> for String { |
712 | #[inline ] |
713 | fn eq(&self, other: &HeaderValue) -> bool { |
714 | *other == *self |
715 | } |
716 | } |
717 | |
718 | impl PartialOrd<HeaderValue> for String { |
719 | #[inline ] |
720 | fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> { |
721 | self.as_bytes().partial_cmp(other.as_bytes()) |
722 | } |
723 | } |
724 | |
725 | impl<'a> PartialEq<HeaderValue> for &'a HeaderValue { |
726 | #[inline ] |
727 | fn eq(&self, other: &HeaderValue) -> bool { |
728 | **self == *other |
729 | } |
730 | } |
731 | |
732 | impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue { |
733 | #[inline ] |
734 | fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> { |
735 | (**self).partial_cmp(other) |
736 | } |
737 | } |
738 | |
739 | impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue |
740 | where |
741 | HeaderValue: PartialEq<T>, |
742 | { |
743 | #[inline ] |
744 | fn eq(&self, other: &&'a T) -> bool { |
745 | *self == **other |
746 | } |
747 | } |
748 | |
749 | impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue |
750 | where |
751 | HeaderValue: PartialOrd<T>, |
752 | { |
753 | #[inline ] |
754 | fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> { |
755 | self.partial_cmp(*other) |
756 | } |
757 | } |
758 | |
759 | impl<'a> PartialEq<HeaderValue> for &'a str { |
760 | #[inline ] |
761 | fn eq(&self, other: &HeaderValue) -> bool { |
762 | *other == *self |
763 | } |
764 | } |
765 | |
766 | impl<'a> PartialOrd<HeaderValue> for &'a str { |
767 | #[inline ] |
768 | fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> { |
769 | self.as_bytes().partial_cmp(other.as_bytes()) |
770 | } |
771 | } |
772 | |
773 | #[test] |
774 | fn test_try_from() { |
775 | HeaderValue::try_from(vec![127]).unwrap_err(); |
776 | } |
777 | |
778 | #[test] |
779 | fn test_debug() { |
780 | let cases = &[ |
781 | ("hello" , " \"hello \"" ), |
782 | ("hello \"world \"" , " \"hello \\\"world \\\"\"" ), |
783 | (" \u{7FFF}hello" , " \"\\xe7 \\xbf \\xbfhello \"" ), |
784 | ]; |
785 | |
786 | for &(value, expected) in cases { |
787 | let val = HeaderValue::from_bytes(value.as_bytes()).unwrap(); |
788 | let actual = format!("{:?}" , val); |
789 | assert_eq!(expected, actual); |
790 | } |
791 | |
792 | let mut sensitive = HeaderValue::from_static("password" ); |
793 | sensitive.set_sensitive(true); |
794 | assert_eq!("Sensitive" , format!("{:?}" , sensitive)); |
795 | } |
796 | |