11use bytes:: { Bytes , BytesMut } ;
22
3+ use core:: ops:: RangeBounds ;
34use std:: convert:: TryFrom ;
45use std:: error:: Error ;
56use std:: fmt:: Write ;
@@ -157,6 +158,62 @@ impl HeaderValue {
157158 HeaderValue :: try_from_generic ( src, Bytes :: copy_from_slice, is_valid_ascii_or_opaque_byte)
158159 }
159160
161+ /// Convert a [`Bytes`] into a `HeaderValue`.
162+ ///
163+ /// This function will not perform any copying.
164+ ///
165+ /// If the argument contains invalid header value bytes, an error is
166+ /// returned. Only byte values between 32 and 255 (inclusive) are permitted,
167+ /// excluding byte 127 (DEL).
168+ ///
169+ /// # Examples
170+ ///
171+ /// ```
172+ /// # use http::header::HeaderValue;
173+ /// # use bytes::Bytes;
174+ /// let bytes = Bytes::from_static(b"hello\xfa");
175+ /// let val = HeaderValue::from_shared(bytes).unwrap();
176+ /// assert_eq!(val, &b"hello\xfa"[..]);
177+ /// ```
178+ pub fn from_shared ( src : Bytes ) -> Result < HeaderValue , InvalidHeaderValue > {
179+ for & b in src. as_ref ( ) {
180+ if !is_valid_ascii_or_opaque_byte ( b) {
181+ return Err ( InvalidHeaderValue { _priv : ( ) } ) ;
182+ }
183+ }
184+ Ok ( HeaderValue {
185+ inner : src,
186+ is_sensitive : false ,
187+ } )
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+ ///
195+ /// ## Panics
196+ /// In a debug build this will panic if `src` is not valid UTF-8.
197+ ///
198+ /// ## Safety
199+ /// `src` must contain valid UTF-8. In a release build it is undefined
200+ /// behaviour to call this with `src` that is not valid UTF-8.
201+ pub unsafe fn from_shared_unchecked ( src : Bytes ) -> HeaderValue {
202+ if cfg ! ( debug_assertions) {
203+ match HeaderValue :: from_shared ( src) {
204+ Ok ( val) => val,
205+ Err ( _err) => {
206+ panic ! ( "HeaderValue::from_shared_unchecked() with invalid bytes" ) ;
207+ }
208+ }
209+ } else {
210+ return HeaderValue {
211+ inner : src,
212+ is_sensitive : false ,
213+ } ;
214+ }
215+ }
216+
160217 /// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
161218 ///
162219 /// This will try to prevent a copy if the type passed is the type used
@@ -210,10 +267,6 @@ impl HeaderValue {
210267 }
211268 }
212269
213- fn from_shared ( src : Bytes ) -> Result < HeaderValue , InvalidHeaderValue > {
214- HeaderValue :: try_from_generic ( src, std:: convert:: identity, is_valid_ascii_or_opaque_byte)
215- }
216-
217270 fn try_from_generic < T : AsRef < [ u8 ] > , F : FnOnce ( T ) -> Bytes , V : Fn ( u8 ) -> bool > (
218271 src : T ,
219272 into : F ,
@@ -308,6 +361,148 @@ impl HeaderValue {
308361 self . as_ref ( )
309362 }
310363
364+ /// Creates a new [`Bytes`] object from this `HeaderValue`.
365+ ///
366+ /// This function will not perform any copying. Rather, it allocates a new,
367+ /// owned `Bytes` object (which will be, at the time of writing, roughly 4
368+ /// pointers in size) which will claim a reference-counted borrow of the
369+ /// shared memory region that backs this `HeaderValue`. Because of the
370+ /// Arc-like semantics of `Bytes` and `HeaderValue`s, this `HeaderValue` and
371+ /// the returned `Bytes` can be dropped in any order and the shared memory
372+ /// region will remain valid for the other.
373+ ///
374+ /// # Examples
375+ ///
376+ /// ```
377+ /// # use http::header::HeaderValue;
378+ /// # use bytes::Bytes;
379+ /// let val = HeaderValue::from_static("hello");
380+ /// assert_eq!(val.as_shared(), Bytes::from_static(b"hello"));
381+ /// ```
382+ #[ inline]
383+ pub fn as_shared ( & self ) -> Bytes {
384+ self . inner . clone ( )
385+ }
386+
387+ /// Return the inner [`Bytes`] object, consuming this `HeaderValue`.
388+ ///
389+ /// Unlike [`as_shared()`], this method will not increment the reference
390+ /// count of the shared memory region that backs this `HeaderValue`. This
391+ /// method consumes `self` to do so.
392+ ///
393+ /// # Examples
394+ ///
395+ /// ```
396+ /// # use http::header::HeaderValue;
397+ /// # use bytes::Bytes;
398+ /// let val = HeaderValue::from_static("hello");
399+ /// assert_eq!(val.into_shared(), Bytes::from_static(b"hello"));
400+ /// ```
401+ ///
402+ /// [`as_shared()`]: Self::as_shared()
403+ #[ inline]
404+ pub fn into_shared ( self ) -> Bytes {
405+ self . inner
406+ }
407+
408+ /// Returns a slice of `self` over the provided range.
409+ ///
410+ ///
411+ /// This function will not perform any copying. Rather, it allocates a new,
412+ /// owned `HeaderValue` object (which will be, at the time of writing,
413+ /// roughly 5 pointers in size) which will claim a reference-counted borrow
414+ /// of the shared memory region that backs this `HeaderValue`. Because of the
415+ /// Arc-like semantics of`HeaderValue`s, this and the resulting
416+ /// `HeaderValue` can be dropped in any order and the shared memory region
417+ /// will remain valid for the other.
418+ ///
419+ /// If the `range` would be out of bounds, this function will return `None`.
420+ ///
421+ /// # Examples
422+ ///
423+ /// ```
424+ /// # use http::header::HeaderValue;
425+ /// let val = HeaderValue::from_static(r#"W/"67ab43", "54ed21", "7892dd""#);
426+ /// let slice_1 = val.try_slice(0..10).unwrap();
427+ /// let slice_3 = val.try_slice(22..30).unwrap();
428+ /// assert_eq!(slice_1, r#"W/"67ab43""#);
429+ /// assert_eq!(slice_3, "\"7892dd\"");
430+ /// assert!(val.try_slice(0..31).is_none());
431+ /// ```
432+ #[ inline]
433+ pub fn try_slice ( & self , range : impl RangeBounds < usize > ) -> Option < HeaderValue > {
434+ use core:: ops:: Bound ;
435+
436+ let len = self . len ( ) ;
437+
438+ let begin = match range. start_bound ( ) {
439+ Bound :: Included ( & n) => n,
440+ Bound :: Excluded ( & n) => {
441+ if let Some ( n) = n. checked_add ( 1 ) {
442+ n
443+ } else {
444+ return None ;
445+ }
446+ }
447+ Bound :: Unbounded => 0 ,
448+ } ;
449+
450+ let end = match range. end_bound ( ) {
451+ Bound :: Included ( & n) => {
452+ if let Some ( n) = n. checked_add ( 1 ) {
453+ n
454+ } else {
455+ return None ;
456+ }
457+ }
458+ Bound :: Excluded ( & n) => n,
459+ Bound :: Unbounded => len,
460+ } ;
461+
462+ if begin > end {
463+ return None ;
464+ }
465+ if end > len {
466+ return None ;
467+ }
468+
469+ Some ( self . slice ( range) )
470+ }
471+
472+ /// Returns a slice of `self` over the provided range.
473+ ///
474+ ///
475+ /// This function will not perform any copying. Rather, it allocates a new,
476+ /// owned `HeaderValue` object (which will be, at the time of writing,
477+ /// roughly 5 pointers in size) which will claim a reference-counted borrow
478+ /// of the shared memory region that backs this `HeaderValue`. Because of the
479+ /// Arc-like semantics of`HeaderValue`s, this and the resulting
480+ /// `HeaderValue` can be dropped in any order and the shared memory region
481+ /// will remain valid for the other.
482+ ///
483+ /// # Panics
484+ ///
485+ /// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing
486+ /// will panic.
487+ ///
488+ /// # Examples
489+ ///
490+ /// ```
491+ /// # use http::header::HeaderValue;
492+ /// let val = HeaderValue::from_static(r#"W/"67ab43", "54ed21", "7892dd""#);
493+ /// let slice_1 = val.slice(0..10);
494+ /// let slice_3 = val.slice(22..30);
495+ /// assert_eq!(slice_1, r#"W/"67ab43""#);
496+ /// assert_eq!(slice_3, "\"7892dd\"");
497+ /// ```
498+ #[ inline]
499+ pub fn slice ( & self , range : impl RangeBounds < usize > ) -> HeaderValue {
500+ let inner_slice = self . inner . slice ( range) ;
501+ // SAFETY: Any subslice of `self.inner` should be just as valid for use
502+ // as a HeaderValue as the full `self.inner` buffer.
503+ unsafe { HeaderValue :: from_shared_unchecked ( inner_slice) }
504+ }
505+
311506 /// Mark that the header value represents sensitive information.
312507 ///
313508 /// # Examples
@@ -398,7 +593,7 @@ impl From<HeaderName> for HeaderValue {
398593 #[ inline]
399594 fn from ( h : HeaderName ) -> HeaderValue {
400595 HeaderValue {
401- inner : h. into_bytes ( ) ,
596+ inner : h. into_shared ( ) ,
402597 is_sensitive : false ,
403598 }
404599 }
@@ -561,6 +756,7 @@ mod try_from_header_name_tests {
561756 }
562757}
563758
759+ #[ inline]
564760const fn is_valid_ascii ( b : u8 ) -> bool {
565761 b >= 32 && b < 127 || b == b'\t'
566762}
@@ -569,7 +765,7 @@ const fn is_valid_ascii(b: u8) -> bool {
569765// may contain opaque bytes, even though those bytes cannot be exposed by
570766// `HeaderValue::to_str`.
571767#[ inline]
572- fn is_valid_ascii_or_opaque_byte ( b : u8 ) -> bool {
768+ const fn is_valid_ascii_or_opaque_byte ( b : u8 ) -> bool {
573769 b >= 32 && b != 127 || b == b'\t'
574770}
575771
0 commit comments