Coverage Report

Created: 2026-08-31 06:59

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