From 50d6297d23df6fe5ae83bf88e5b316b7d21bf85e Mon Sep 17 00:00:00 2001 From: Jason Hinch <594559+jhinch@users.noreply.github.com> Date: Tue, 7 Jan 2020 22:20:04 +1100 Subject: [PATCH] Replace unsafe code by ByteStr (fixes #440) --- src/frame/headers.rs | 24 +++++++++++------------- src/hpack/decoder.rs | 14 +++++--------- src/hpack/header.rs | 8 ++++++-- src/hpack/test/fuzz.rs | 5 ++--- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/frame/headers.rs b/src/frame/headers.rs index 979ac70..0b900de 100644 --- a/src/frame/headers.rs +++ b/src/frame/headers.rs @@ -5,7 +5,7 @@ use crate::hpack::{self, BytesStr}; use http::header::{self, HeaderName, HeaderValue}; use http::{uri, HeaderMap, Method, Request, StatusCode, Uri}; -use bytes::{Bytes, BytesMut}; +use bytes::BytesMut; use std::fmt; use std::io::Cursor; @@ -549,13 +549,13 @@ impl Pseudo { let mut path = parts .path_and_query - .map(|v| Bytes::copy_from_slice(v.as_str().as_bytes())) - .unwrap_or_else(Bytes::new); + .map(|v| BytesStr::from(v.as_str())) + .unwrap_or(BytesStr::from_static("")); match method { Method::OPTIONS | Method::CONNECT => {} _ if path.is_empty() => { - path = Bytes::from_static(b"/"); + path = BytesStr::from_static("/"); } _ => {} } @@ -564,7 +564,7 @@ impl Pseudo { method: Some(method), scheme: None, authority: None, - path: Some(unsafe { BytesStr::from_utf8_unchecked(path) }).filter(|p| !p.is_empty()), + path: Some(path).filter(|p| !p.is_empty()), status: None, }; @@ -578,9 +578,7 @@ impl Pseudo { // If the URI includes an authority component, add it to the pseudo // headers if let Some(authority) = parts.authority { - pseudo.set_authority(unsafe { - BytesStr::from_utf8_unchecked(Bytes::copy_from_slice(authority.as_str().as_bytes())) - }); + pseudo.set_authority(BytesStr::from(authority.as_str())); } pseudo @@ -597,12 +595,12 @@ impl Pseudo { } pub fn set_scheme(&mut self, scheme: uri::Scheme) { - let bytes = match scheme.as_str() { - "http" => Bytes::from_static(b"http"), - "https" => Bytes::from_static(b"https"), - s => Bytes::copy_from_slice(s.as_bytes()), + let bytes_str = match scheme.as_str() { + "http" => BytesStr::from_static("http"), + "https" => BytesStr::from_static("https"), + s => BytesStr::from(s), }; - self.scheme = Some(unsafe { BytesStr::from_utf8_unchecked(bytes) }); + self.scheme = Some(bytes_str); } pub fn set_authority(&mut self, authority: BytesStr) { diff --git a/src/hpack/decoder.rs b/src/hpack/decoder.rs index 39afc8a..dacbbd9 100644 --- a/src/hpack/decoder.rs +++ b/src/hpack/decoder.rs @@ -577,13 +577,13 @@ pub fn get_static(idx: usize) -> Header { use http::header::HeaderValue; match idx { - 1 => Header::Authority(from_static("")), + 1 => Header::Authority(BytesStr::from_static("")), 2 => Header::Method(Method::GET), 3 => Header::Method(Method::POST), - 4 => Header::Path(from_static("/")), - 5 => Header::Path(from_static("/index.html")), - 6 => Header::Scheme(from_static("http")), - 7 => Header::Scheme(from_static("https")), + 4 => Header::Path(BytesStr::from_static("/")), + 5 => Header::Path(BytesStr::from_static("/index.html")), + 6 => Header::Scheme(BytesStr::from_static("http")), + 7 => Header::Scheme(BytesStr::from_static("https")), 8 => Header::Status(StatusCode::OK), 9 => Header::Status(StatusCode::NO_CONTENT), 10 => Header::Status(StatusCode::PARTIAL_CONTENT), @@ -783,10 +783,6 @@ pub fn get_static(idx: usize) -> Header { } } -fn from_static(s: &'static str) -> BytesStr { - unsafe { BytesStr::from_utf8_unchecked(Bytes::from_static(s.as_bytes())) } -} - #[cfg(test)] mod test { use super::*; diff --git a/src/hpack/header.rs b/src/hpack/header.rs index 7436950..e5b1a34 100644 --- a/src/hpack/header.rs +++ b/src/hpack/header.rs @@ -246,8 +246,12 @@ impl<'a> Name<'a> { // ===== impl BytesStr ===== impl BytesStr { - pub(crate) unsafe fn from_utf8_unchecked(bytes: Bytes) -> Self { - BytesStr(bytes) + pub(crate) const fn from_static(value: &'static str) -> Self { + BytesStr(Bytes::from_static(value.as_bytes())) + } + + pub(crate) fn from(value: &str) -> Self { + BytesStr(Bytes::copy_from_slice(value.as_bytes())) } #[doc(hidden)] diff --git a/src/hpack/test/fuzz.rs b/src/hpack/test/fuzz.rs index 0abb66a..d4e6534 100644 --- a/src/hpack/test/fuzz.rs +++ b/src/hpack/test/fuzz.rs @@ -2,7 +2,7 @@ use crate::hpack::{Decoder, Encode, Encoder, Header}; use http::header::{HeaderName, HeaderValue}; -use bytes::{buf::BufMut, Bytes, BytesMut}; +use bytes::{buf::BufMut, BytesMut}; use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult}; use rand::{Rng, SeedableRng, StdRng}; @@ -404,6 +404,5 @@ fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String { } fn to_shared(src: String) -> crate::hpack::BytesStr { - let b: Bytes = src.into(); - unsafe { crate::hpack::BytesStr::from_utf8_unchecked(b) } + crate::hpack::BytesStr::from(src.as_str()) }