http_with_url/header/
value.rs1use bytes::Bytes;
2
3use std::{cmp, fmt, str};
4use std::error::Error;
5use std::str::FromStr;
6
7use ::convert::HttpTryFrom;
8use header::name::HeaderName;
9
10#[derive(Clone, Hash)]
20pub struct HeaderValue {
21 inner: Bytes,
22 is_sensitive: bool,
23}
24
25#[derive(Debug)]
28pub struct InvalidHeaderValue {
29 _priv: (),
30}
31
32#[derive(Debug)]
35pub struct InvalidHeaderValueBytes(InvalidHeaderValue);
36
37#[derive(Debug)]
42pub struct ToStrError {
43 _priv: (),
44}
45
46impl HeaderValue {
47 #[inline]
66 pub fn from_static(src: &'static str) -> HeaderValue {
67 let bytes = src.as_bytes();
68 for &b in bytes {
69 if !is_visible_ascii(b) {
70 panic!("invalid header value");
71 }
72 }
73
74 HeaderValue {
75 inner: Bytes::from_static(bytes),
76 is_sensitive: false,
77 }
78 }
79
80 #[inline]
106 pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
107 HeaderValue::try_from(src)
108 }
109
110 #[inline]
123 pub fn from_name(name: HeaderName) -> HeaderValue {
124 name.into()
125 }
126
127 #[inline]
152 pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
153 HeaderValue::try_from(src)
154 }
155
156 #[inline]
165 pub fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValueBytes> {
166 HeaderValue::try_from(src).map_err(InvalidHeaderValueBytes)
167 }
168
169 #[inline]
174 pub unsafe fn from_shared_unchecked(src: Bytes) -> HeaderValue {
175 HeaderValue {
176 inner: src,
177 is_sensitive: false,
178 }
179 }
180
181 fn try_from<T: AsRef<[u8]> + Into<Bytes>>(src: T) -> Result<HeaderValue, InvalidHeaderValue> {
182 for &b in src.as_ref() {
183 if !is_valid(b) {
184 return Err(InvalidHeaderValue {
185 _priv: (),
186 });
187 }
188 }
189 Ok(HeaderValue {
190 inner: src.into(),
191 is_sensitive: false,
192 })
193 }
194
195 pub fn to_str(&self) -> Result<&str, ToStrError> {
209 let bytes = self.as_ref();
210
211 for &b in bytes {
212 if !is_visible_ascii(b) {
213 return Err(ToStrError { _priv: () });
214 }
215 }
216
217 unsafe { Ok(str::from_utf8_unchecked(bytes)) }
218 }
219
220 #[inline]
232 pub fn len(&self) -> usize {
233 self.as_ref().len()
234 }
235
236 #[inline]
249 pub fn is_empty(&self) -> bool {
250 self.len() == 0
251 }
252
253 #[inline]
263 pub fn as_bytes(&self) -> &[u8] {
264 self.as_ref()
265 }
266
267 #[inline]
282 pub fn set_sensitive(&mut self, val: bool) {
283 self.is_sensitive = val;
284 }
285
286 #[inline]
308 pub fn is_sensitive(&self) -> bool {
309 self.is_sensitive
310 }
311}
312
313impl AsRef<[u8]> for HeaderValue {
314 #[inline]
315 fn as_ref(&self) -> &[u8] {
316 self.inner.as_ref()
317 }
318}
319
320impl fmt::Debug for HeaderValue {
321 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322 if self.is_sensitive {
323 f.write_str("Sensitive")
324 } else {
325 f.write_str("\"")?;
326 let mut from = 0;
327 let bytes = self.as_bytes();
328 for (i, &b) in bytes.iter().enumerate() {
329 if !is_visible_ascii(b) || b == b'"' {
330 if from != i {
331 f.write_str(unsafe {
332 str::from_utf8_unchecked(&bytes[from..i])
333 })?;
334 }
335 if b == b'"' {
336 f.write_str("\\\"")?;
337 } else {
338 write!(f, "\\x{:x}", b)?;
339 }
340 from = i + 1;
341 }
342 }
343
344 f.write_str(unsafe {
345 str::from_utf8_unchecked(&bytes[from..])
346 })?;
347 f.write_str("\"")
348 }
349 }
350}
351
352impl From<HeaderName> for HeaderValue {
353 #[inline]
354 fn from(h: HeaderName) -> HeaderValue {
355 HeaderValue {
356 inner: h.into(),
357 is_sensitive: false,
358 }
359 }
360}
361
362#[cfg(test)]
363mod from_header_name_tests {
364 use super::*;
365 use header::map::HeaderMap;
366 use header::name;
367
368 #[test]
369 fn it_can_insert_header_name_as_header_value() {
370 let mut map = HeaderMap::new();
371 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
372 map.insert(name::ACCEPT, name::HeaderName::from_bytes(b"hello-world").unwrap().into());
373
374 assert_eq!(
375 map.get(name::UPGRADE).unwrap(),
376 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
377 );
378
379 assert_eq!(
380 map.get(name::ACCEPT).unwrap(),
381 HeaderValue::from_bytes(b"hello-world").unwrap()
382 );
383 }
384}
385
386impl FromStr for HeaderValue {
387 type Err = InvalidHeaderValue;
388
389 #[inline]
390 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
391 HeaderValue::from_str(s)
392 }
393}
394
395impl From<HeaderValue> for Bytes {
396 #[inline]
397 fn from(value: HeaderValue) -> Bytes {
398 value.inner
399 }
400}
401
402impl<'a> HttpTryFrom<&'a str> for HeaderValue {
403 type Error = InvalidHeaderValue;
404
405 #[inline]
406 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
407 t.parse()
408 }
409}
410
411impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue {
412 type Error = InvalidHeaderValue;
413
414 #[inline]
415 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
416 HeaderValue::from_bytes(t)
417 }
418}
419
420impl HttpTryFrom<Bytes> for HeaderValue {
421 type Error = InvalidHeaderValueBytes;
422
423 #[inline]
424 fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
425 HeaderValue::from_shared(bytes)
426 }
427}
428
429impl HttpTryFrom<HeaderName> for HeaderValue {
430 type Error = InvalidHeaderValue;
431
432 #[inline]
433 fn try_from(name: HeaderName) -> Result<Self, Self::Error> {
434 Ok(name.into())
436 }
437}
438
439#[cfg(test)]
440mod try_from_header_name_tests {
441 use super::*;
442 use header::name;
443
444 #[test]
445 fn it_converts_using_try_from() {
446 assert_eq!(
447 HeaderValue::try_from(name::UPGRADE).unwrap(),
448 HeaderValue::from_bytes(b"upgrade").unwrap()
449 );
450 }
451}
452
453fn is_visible_ascii(b: u8) -> bool {
454 b >= 32 && b < 127
455}
456
457#[inline]
458fn is_valid(b: u8) -> bool {
459 b >= 32 && b != 127
460}
461
462impl fmt::Display for InvalidHeaderValue {
463 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
464 self.description().fmt(f)
465 }
466}
467
468impl Error for InvalidHeaderValue {
469 fn description(&self) -> &str {
470 "failed to parse header value"
471 }
472}
473
474impl fmt::Display for InvalidHeaderValueBytes {
475 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
476 self.0.fmt(f)
477 }
478}
479
480impl Error for InvalidHeaderValueBytes {
481 fn description(&self) -> &str {
482 self.0.description()
483 }
484}
485
486impl fmt::Display for ToStrError {
487 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
488 self.description().fmt(f)
489 }
490}
491
492impl Error for ToStrError {
493 fn description(&self) -> &str {
494 "failed to convert header to a str"
495 }
496}
497
498impl PartialEq for HeaderValue {
501 #[inline]
502 fn eq(&self, other: &HeaderValue) -> bool {
503 self.inner == other.inner
504 }
505}
506
507impl Eq for HeaderValue {}
508
509impl PartialOrd for HeaderValue {
510 #[inline]
511 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
512 self.inner.partial_cmp(&other.inner)
513 }
514}
515
516impl Ord for HeaderValue {
517 #[inline]
518 fn cmp(&self, other: &Self) -> cmp::Ordering {
519 self.inner.cmp(&other.inner)
520 }
521}
522
523impl PartialEq<str> for HeaderValue {
524 #[inline]
525 fn eq(&self, other: &str) -> bool {
526 self.inner == other.as_bytes()
527 }
528}
529
530impl PartialEq<[u8]> for HeaderValue {
531 #[inline]
532 fn eq(&self, other: &[u8]) -> bool {
533 self.inner == other
534 }
535}
536
537impl PartialOrd<str> for HeaderValue {
538 #[inline]
539 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
540 (*self.inner).partial_cmp(other.as_bytes())
541 }
542}
543
544impl PartialOrd<[u8]> for HeaderValue {
545 #[inline]
546 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
547 (*self.inner).partial_cmp(other)
548 }
549}
550
551impl PartialEq<HeaderValue> for str {
552 #[inline]
553 fn eq(&self, other: &HeaderValue) -> bool {
554 *other == *self
555 }
556}
557
558impl PartialEq<HeaderValue> for [u8] {
559 #[inline]
560 fn eq(&self, other: &HeaderValue) -> bool {
561 *other == *self
562 }
563}
564
565impl PartialOrd<HeaderValue> for str {
566 #[inline]
567 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
568 self.as_bytes().partial_cmp(other.as_bytes())
569 }
570}
571
572impl PartialOrd<HeaderValue> for [u8] {
573 #[inline]
574 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
575 self.partial_cmp(other.as_bytes())
576 }
577}
578
579impl PartialEq<String> for HeaderValue {
580 #[inline]
581 fn eq(&self, other: &String) -> bool {
582 *self == &other[..]
583 }
584}
585
586impl PartialOrd<String> for HeaderValue {
587 #[inline]
588 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
589 self.inner.partial_cmp(other.as_bytes())
590 }
591}
592
593impl PartialEq<HeaderValue> for String {
594 #[inline]
595 fn eq(&self, other: &HeaderValue) -> bool {
596 *other == *self
597 }
598}
599
600impl PartialOrd<HeaderValue> for String {
601 #[inline]
602 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
603 self.as_bytes().partial_cmp(other.as_bytes())
604 }
605}
606
607impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
608 #[inline]
609 fn eq(&self, other: &HeaderValue) -> bool {
610 **self == *other
611 }
612}
613
614impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
615 #[inline]
616 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
617 (**self).partial_cmp(other)
618 }
619}
620
621impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
622 where HeaderValue: PartialEq<T>
623{
624 #[inline]
625 fn eq(&self, other: &&'a T) -> bool {
626 *self == **other
627 }
628}
629
630impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
631 where HeaderValue: PartialOrd<T>
632{
633 #[inline]
634 fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
635 self.partial_cmp(*other)
636 }
637}
638
639impl<'a> PartialEq<HeaderValue> for &'a str {
640 #[inline]
641 fn eq(&self, other: &HeaderValue) -> bool {
642 *other == *self
643 }
644}
645
646impl<'a> PartialOrd<HeaderValue> for &'a str {
647 #[inline]
648 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
649 self.as_bytes().partial_cmp(other.as_bytes())
650 }
651}
652
653#[test]
654fn test_try_from() {
655 HeaderValue::try_from(vec![127]).unwrap_err();
656}
657
658#[test]
659fn test_debug() {
660 let cases = &[
661 ("hello", "\"hello\""),
662 ("hello \"world\"", "\"hello \\\"world\\\"\""),
663 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
664 ];
665
666 for &(value, expected) in cases {
667 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
668 let actual = format!("{:?}", val);
669 assert_eq!(expected, actual);
670 }
671
672 let mut sensitive = HeaderValue::from_static("password");
673 sensitive.set_sensitive(true);
674 assert_eq!("Sensitive", format!("{:?}", sensitive));
675}