Merge pull request #1038 from hyperium/headers-mem-slice
use MemSlice in Headers
This commit is contained in:
@@ -40,6 +40,7 @@ impl Header for ContentLength {
|
||||
static NAME: &'static str = "Content-Length";
|
||||
NAME
|
||||
}
|
||||
|
||||
fn parse_header(raw: &Raw) -> ::Result<ContentLength> {
|
||||
// If multiple Content-Length headers were sent, everything can still
|
||||
// be alright if they all contain the same value, and all parse
|
||||
@@ -49,9 +50,9 @@ impl Header for ContentLength {
|
||||
.fold(None, |prev, x| {
|
||||
match (prev, x) {
|
||||
(None, x) => Some(x),
|
||||
(e@Some(Err(_)), _ ) => e,
|
||||
(e @ Some(Err(_)), _ ) => e,
|
||||
(Some(Ok(prev)), Ok(x)) if prev == x => Some(Ok(prev)),
|
||||
_ => Some(Err(::Error::Header))
|
||||
_ => Some(Err(::Error::Header)),
|
||||
}
|
||||
})
|
||||
.unwrap_or(Err(::Error::Header))
|
||||
|
||||
@@ -141,9 +141,7 @@ impl Header for RetryAfter {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate httparse;
|
||||
|
||||
use header::{Header, Headers};
|
||||
use header::Header;
|
||||
use header::shared::HttpDate;
|
||||
use time::{Duration};
|
||||
|
||||
@@ -179,17 +177,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn hyper_headers_from_raw_delay() {
|
||||
let headers = Headers::from_raw(&[httparse::Header { name: "Retry-After", value: b"300" }]).unwrap();
|
||||
let retry_after = headers.get::<RetryAfter>().unwrap();
|
||||
assert_eq!(retry_after, &RetryAfter::Delay(Duration::seconds(300)));
|
||||
let retry_after = RetryAfter::parse_header(&b"300".to_vec().into()).unwrap();
|
||||
assert_eq!(retry_after, RetryAfter::Delay(Duration::seconds(300)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hyper_headers_from_raw_datetime() {
|
||||
let headers = Headers::from_raw(&[httparse::Header { name: "Retry-After", value: b"Sun, 06 Nov 1994 08:49:37 GMT" }]).unwrap();
|
||||
let retry_after = headers.get::<RetryAfter>().unwrap();
|
||||
let retry_after = RetryAfter::parse_header(&b"Sun, 06 Nov 1994 08:49:37 GMT".to_vec().into()).unwrap();
|
||||
let expected = "Sun, 06 Nov 1994 08:49:37 GMT".parse::<HttpDate>().unwrap();
|
||||
|
||||
assert_eq!(retry_after, &RetryAfter::DateTime(expected.0));
|
||||
assert_eq!(retry_after, RetryAfter::DateTime(expected.0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ pub struct VecMap<K, V> {
|
||||
}
|
||||
|
||||
impl<K: PartialEq, V> VecMap<K, V> {
|
||||
pub fn new() -> VecMap<K, V> {
|
||||
pub fn with_capacity(cap: usize) -> VecMap<K, V> {
|
||||
VecMap {
|
||||
vec: Vec::new()
|
||||
vec: Vec::with_capacity(cap)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ impl<K: PartialEq, V> VecMap<K, V> {
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize { self.vec.len() }
|
||||
|
||||
pub fn iter(&self) -> ::std::slice::Iter<(K, V)> {
|
||||
self.vec.iter()
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ use std::borrow::{Cow, ToOwned};
|
||||
use std::iter::{FromIterator, IntoIterator};
|
||||
use std::{mem, fmt};
|
||||
|
||||
use httparse;
|
||||
use unicase::UniCase;
|
||||
|
||||
use self::internals::{Item, VecMap, Entry};
|
||||
@@ -88,6 +87,7 @@ use self::internals::{Item, VecMap, Entry};
|
||||
pub use self::shared::*;
|
||||
pub use self::common::*;
|
||||
pub use self::raw::Raw;
|
||||
use http::buf::MemSlice;
|
||||
|
||||
mod common;
|
||||
mod internals;
|
||||
@@ -346,33 +346,19 @@ literals! {
|
||||
impl Headers {
|
||||
|
||||
/// Creates a new, empty headers map.
|
||||
#[inline]
|
||||
pub fn new() -> Headers {
|
||||
Headers::with_capacity(0)
|
||||
}
|
||||
|
||||
/// Creates a new `Headers` struct with space reserved for `len` headers.
|
||||
#[inline]
|
||||
pub fn with_capacity(len: usize) -> Headers {
|
||||
Headers {
|
||||
data: VecMap::new()
|
||||
data: VecMap::with_capacity(len)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn from_raw(raw: &[httparse::Header]) -> ::Result<Headers> {
|
||||
let mut headers = Headers::new();
|
||||
for header in raw {
|
||||
trace!("raw header: {:?}={:?}", header.name, &header.value[..]);
|
||||
let name = HeaderName(UniCase(maybe_literal(header.name)));
|
||||
let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count();
|
||||
let value = &header.value[.. header.value.len() - trim];
|
||||
|
||||
match headers.data.entry(name) {
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(Item::new_raw(self::raw::parsed(value)));
|
||||
}
|
||||
Entry::Occupied(entry) => {
|
||||
entry.into_mut().mut_raw().push(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(headers)
|
||||
}
|
||||
|
||||
/// Set a header field to the corresponding value.
|
||||
///
|
||||
/// The field is determined by the type of the value being set.
|
||||
@@ -586,6 +572,24 @@ impl<'a> Extend<HeaderView<'a>> for Headers {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Extend<(&'a str, MemSlice)> for Headers {
|
||||
fn extend<I: IntoIterator<Item=(&'a str, MemSlice)>>(&mut self, iter: I) {
|
||||
for (name, value) in iter {
|
||||
let name = HeaderName(UniCase(maybe_literal(name)));
|
||||
//let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count();
|
||||
|
||||
match self.data.entry(name) {
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(Item::new_raw(self::raw::parsed(value)));
|
||||
}
|
||||
Entry::Occupied(entry) => {
|
||||
self::raw::push(entry.into_mut().mut_raw(), value);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<HeaderView<'a>> for Headers {
|
||||
fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
|
||||
let mut headers = Headers::new();
|
||||
@@ -658,37 +662,25 @@ mod tests {
|
||||
use mime::SubLevel::Plain;
|
||||
use super::{Headers, Header, Raw, ContentLength, ContentType,
|
||||
Accept, Host, qitem};
|
||||
use httparse;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use test::Bencher;
|
||||
|
||||
// Slice.position_elem was unstable
|
||||
fn index_of(slice: &[u8], byte: u8) -> Option<usize> {
|
||||
for (index, &b) in slice.iter().enumerate() {
|
||||
if b == byte {
|
||||
return Some(index);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
macro_rules! raw {
|
||||
($($line:expr),*) => ({
|
||||
[$({
|
||||
let line = $line;
|
||||
let pos = index_of(line, b':').expect("raw splits on ':', not found");
|
||||
httparse::Header {
|
||||
name: ::std::str::from_utf8(&line[..pos]).unwrap(),
|
||||
value: &line[pos + 2..]
|
||||
}
|
||||
}),*]
|
||||
macro_rules! make_header {
|
||||
($name:expr, $value:expr) => ({
|
||||
let mut headers = Headers::new();
|
||||
headers.set_raw(String::from_utf8($name.to_vec()).unwrap(), $value.to_vec());
|
||||
headers
|
||||
});
|
||||
($text:expr) => ({
|
||||
let bytes = $text;
|
||||
let colon = bytes.iter().position(|&x| x == b':').unwrap();
|
||||
make_header!(&bytes[..colon], &bytes[colon + 2..])
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_raw() {
|
||||
let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
|
||||
let headers = make_header!(b"Content-Length", b"10");
|
||||
assert_eq!(headers.get(), Some(&ContentLength(10)));
|
||||
}
|
||||
|
||||
@@ -738,20 +730,20 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_different_structs_for_same_header() {
|
||||
let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
|
||||
let headers = make_header!(b"Content-Length: 10");
|
||||
assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
|
||||
assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailing_whitespace() {
|
||||
let headers = Headers::from_raw(&raw!(b"Content-Length: 10 ")).unwrap();
|
||||
let headers = make_header!(b"Content-Length: 10 ");
|
||||
assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_reads() {
|
||||
let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
|
||||
let headers = make_header!(b"Content-Length: 10");
|
||||
let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
|
||||
let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
|
||||
assert_eq!(one, two);
|
||||
@@ -759,15 +751,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_different_reads() {
|
||||
let headers = Headers::from_raw(
|
||||
&raw!(b"Content-Length: 10", b"Content-Type: text/plain")).unwrap();
|
||||
let mut headers = Headers::new();
|
||||
headers.set_raw("Content-Length", "10");
|
||||
headers.set_raw("Content-Type", "text/plain");
|
||||
let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
|
||||
let ContentType(_) = *headers.get::<ContentType>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_mutable() {
|
||||
let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
|
||||
let mut headers = make_header!(b"Content-Length: 10");
|
||||
*headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
|
||||
assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
|
||||
assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
|
||||
@@ -786,7 +779,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_headers_to_string_raw() {
|
||||
let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
|
||||
let mut headers = make_header!(b"Content-Length: 10");
|
||||
headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
|
||||
let s = headers.to_string();
|
||||
assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
|
||||
@@ -900,13 +893,6 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[bench]
|
||||
fn bench_headers_from_raw(b: &mut Bencher) {
|
||||
let raw = raw!(b"Content-Length: 10");
|
||||
b.iter(|| Headers::from_raw(&raw).unwrap())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[bench]
|
||||
fn bench_headers_get(b: &mut Bencher) {
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn from_one_raw_str<T: str::FromStr>(raw: &Raw) -> ::Result<T> {
|
||||
|
||||
/// Reads a raw string into a value.
|
||||
pub fn from_raw_str<T: str::FromStr>(raw: &[u8]) -> ::Result<T> {
|
||||
let s = try!(str::from_utf8(raw));
|
||||
let s = try!(str::from_utf8(raw)).trim();
|
||||
T::from_str(s).or(Err(::Error::Header))
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ pub fn from_comma_delimited<T: str::FromStr>(raw: &Raw) -> ::Result<Vec<T>> {
|
||||
"" => None,
|
||||
y => Some(y)
|
||||
})
|
||||
.filter_map(|x| x.parse().ok()))
|
||||
.filter_map(|x| x.trim().parse().ok()))
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use http::buf::MemSlice;
|
||||
|
||||
/// A raw header value.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
@@ -19,8 +20,8 @@ impl Raw {
|
||||
#[inline]
|
||||
pub fn one(&self) -> Option<&[u8]> {
|
||||
match self.0 {
|
||||
Lines::One(ref line) => Some(line),
|
||||
Lines::Many(ref lines) if lines.len() == 1 => Some(&lines[0]),
|
||||
Lines::One(ref line) => Some(line.as_ref()),
|
||||
Lines::Many(ref lines) if lines.len() == 1 => Some(lines[0].as_ref()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@@ -29,37 +30,42 @@ impl Raw {
|
||||
#[inline]
|
||||
pub fn iter(&self) -> RawLines {
|
||||
RawLines {
|
||||
inner: match self.0 {
|
||||
Lines::One(ref line) => unsafe {
|
||||
::std::slice::from_raw_parts(line, 1)
|
||||
}.iter(),
|
||||
Lines::Many(ref lines) => lines.iter()
|
||||
}
|
||||
inner: &self.0,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Append a line to this `Raw` header value.
|
||||
pub fn push(&mut self, val: &[u8]) {
|
||||
self.push_line(maybe_literal(val.into()));
|
||||
}
|
||||
|
||||
fn push_line(&mut self, line: Line) {
|
||||
let lines = ::std::mem::replace(&mut self.0, Lines::Many(Vec::new()));
|
||||
match lines {
|
||||
Lines::One(line) => {
|
||||
self.0 = Lines::Many(vec![line, maybe_literal(val.into())]);
|
||||
Lines::One(one) => {
|
||||
self.0 = Lines::Many(vec![one, line]);
|
||||
}
|
||||
Lines::Many(mut lines) => {
|
||||
lines.push(maybe_literal(val.into()));
|
||||
lines.push(line);
|
||||
self.0 = Lines::Many(lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum Lines {
|
||||
One(Line),
|
||||
Many(Vec<Line>)
|
||||
Many(Vec<Line>),
|
||||
}
|
||||
|
||||
type Line = Cow<'static, [u8]>;
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum Line {
|
||||
Static(&'static [u8]),
|
||||
Owned(Vec<u8>),
|
||||
Shared(MemSlice),
|
||||
}
|
||||
|
||||
fn eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: &[A], b: &[B]) -> bool {
|
||||
if a.len() != b.len() {
|
||||
@@ -123,24 +129,59 @@ impl From<String> for Raw {
|
||||
impl From<Vec<u8>> for Raw {
|
||||
#[inline]
|
||||
fn from(val: Vec<u8>) -> Raw {
|
||||
Raw(Lines::One(Cow::Owned(val)))
|
||||
Raw(Lines::One(Line::from(val)))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Raw {
|
||||
fn from(val: &'static str) -> Raw {
|
||||
Raw(Lines::One(Cow::Borrowed(val.as_bytes())))
|
||||
Raw(Lines::One(Line::Static(val.as_bytes())))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static [u8]> for Raw {
|
||||
fn from(val: &'static [u8]) -> Raw {
|
||||
Raw(Lines::One(Cow::Borrowed(val)))
|
||||
Raw(Lines::One(Line::Static(val)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parsed(val: &[u8]) -> Raw {
|
||||
Raw(Lines::One(maybe_literal(val.into())))
|
||||
impl From<MemSlice> for Raw {
|
||||
#[inline]
|
||||
fn from(val: MemSlice) -> Raw {
|
||||
Raw(Lines::One(Line::Shared(val)))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for Line {
|
||||
#[inline]
|
||||
fn from(val: Vec<u8>) -> Line {
|
||||
Line::Owned(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MemSlice> for Line {
|
||||
#[inline]
|
||||
fn from(val: MemSlice) -> Line {
|
||||
Line::Shared(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Line {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
match *self {
|
||||
Line::Static(ref s) => s,
|
||||
Line::Owned(ref v) => v.as_ref(),
|
||||
Line::Shared(ref m) => m.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parsed(val: MemSlice) -> Raw {
|
||||
Raw(Lines::One(From::from(val)))
|
||||
}
|
||||
|
||||
pub fn push(raw: &mut Raw, val: MemSlice) {
|
||||
raw.push_line(Line::from(val));
|
||||
}
|
||||
|
||||
impl fmt::Debug for Raw {
|
||||
@@ -154,6 +195,7 @@ impl fmt::Debug for Raw {
|
||||
|
||||
impl ::std::ops::Index<usize> for Raw {
|
||||
type Output = [u8];
|
||||
|
||||
fn index(&self, idx: usize) -> &[u8] {
|
||||
match self.0 {
|
||||
Lines::One(ref line) => if idx == 0 {
|
||||
@@ -168,12 +210,12 @@ impl ::std::ops::Index<usize> for Raw {
|
||||
|
||||
macro_rules! literals {
|
||||
($($len:expr => $($value:expr),+;)+) => (
|
||||
fn maybe_literal<'a>(s: Cow<'a, [u8]>) -> Cow<'static, [u8]> {
|
||||
fn maybe_literal<'a>(s: Cow<'a, [u8]>) -> Line {
|
||||
match s.len() {
|
||||
$($len => {
|
||||
$(
|
||||
if s.as_ref() == $value {
|
||||
return Cow::Borrowed($value);
|
||||
return Line::Static($value);
|
||||
}
|
||||
)+
|
||||
})+
|
||||
@@ -181,7 +223,7 @@ macro_rules! literals {
|
||||
_ => ()
|
||||
}
|
||||
|
||||
Cow::Owned(s.into_owned())
|
||||
Line::from(s.into_owned())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -216,7 +258,8 @@ impl<'a> IntoIterator for &'a Raw {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawLines<'a> {
|
||||
inner: ::std::slice::Iter<'a, Cow<'static, [u8]>>
|
||||
inner: &'a Lines,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for RawLines<'a> {
|
||||
@@ -224,6 +267,17 @@ impl<'a> Iterator for RawLines<'a> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a [u8]> {
|
||||
self.inner.next().map(AsRef::as_ref)
|
||||
let current_pos = self.pos;
|
||||
self.pos += 1;
|
||||
match *self.inner {
|
||||
Lines::One(ref line) => {
|
||||
if current_pos == 0 {
|
||||
Some(line.as_ref())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Lines::Many(ref lines) => lines.get(current_pos).map(|l| l.as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
175
src/http/buf.rs
175
src/http/buf.rs
@@ -1,13 +1,14 @@
|
||||
use std::cell::UnsafeCell;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::fmt;
|
||||
use std::io::{self, Read};
|
||||
use std::ops::{Deref, Range, RangeFrom, RangeTo, RangeFull};
|
||||
use std::ops::{Index, Range, RangeFrom, RangeTo, RangeFull};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct MemBuf {
|
||||
buf: Arc<UnsafeCell<Vec<u8>>>,
|
||||
start: usize,
|
||||
start: Cell<usize>,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
@@ -19,13 +20,13 @@ impl MemBuf {
|
||||
pub fn with_capacity(cap: usize) -> MemBuf {
|
||||
MemBuf {
|
||||
buf: Arc::new(UnsafeCell::new(vec![0; cap])),
|
||||
start: 0,
|
||||
start: Cell::new(0),
|
||||
end: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes(&self) -> &[u8] {
|
||||
&self.buf()[self.start..self.end]
|
||||
&self.buf()[self.start.get()..self.end]
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
@@ -33,7 +34,7 @@ impl MemBuf {
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.end - self.start
|
||||
self.end - self.start.get()
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
@@ -41,20 +42,21 @@ impl MemBuf {
|
||||
}
|
||||
|
||||
pub fn read_from<R: Read>(&mut self, io: &mut R) -> io::Result<usize> {
|
||||
let start = self.end - self.start;
|
||||
let start = self.end - self.start.get();
|
||||
let n = try!(io.read(&mut self.buf_mut()[start..]));
|
||||
self.end += n;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
pub fn slice(&mut self, len: usize) -> MemSlice {
|
||||
assert!(self.end - self.start >= len);
|
||||
let start = self.start;
|
||||
self.start += len;
|
||||
pub fn slice(&self, len: usize) -> MemSlice {
|
||||
assert!(self.end - self.start.get() >= len);
|
||||
let start = self.start.get();
|
||||
let end = start + len;
|
||||
self.start.set(end);
|
||||
MemSlice {
|
||||
buf: self.buf.clone(),
|
||||
start: start,
|
||||
end: self.start,
|
||||
end: end,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,18 +69,18 @@ impl MemBuf {
|
||||
}
|
||||
let is_unique = Arc::get_mut(&mut self.buf).is_some();
|
||||
trace!("MemBuf::reserve {} access", if is_unique { "unique" } else { "shared" });
|
||||
if is_unique && remaining + self.start >= needed {
|
||||
if is_unique && remaining + self.start.get() >= needed {
|
||||
// we have unique access, we can mutate this vector
|
||||
trace!("MemBuf::reserve unique access, shifting");
|
||||
unsafe {
|
||||
let mut buf = &mut *self.buf.get();
|
||||
let len = self.len();
|
||||
ptr::copy(
|
||||
buf.as_ptr().offset(self.start as isize),
|
||||
buf.as_ptr().offset(self.start.get() as isize),
|
||||
buf.as_mut_ptr(),
|
||||
len
|
||||
);
|
||||
self.start = 0;
|
||||
self.start.set(0);
|
||||
self.end = len;
|
||||
}
|
||||
} else if is_unique {
|
||||
@@ -109,7 +111,7 @@ impl MemBuf {
|
||||
match Arc::get_mut(&mut self.buf) {
|
||||
Some(_) => {
|
||||
trace!("MemBuf::reset was unique, re-using");
|
||||
self.start = 0;
|
||||
self.start.set(0);
|
||||
self.end = 0;
|
||||
},
|
||||
None => {
|
||||
@@ -119,13 +121,19 @@ impl MemBuf {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "nightly", test))]
|
||||
pub fn restart(&mut self) {
|
||||
Arc::get_mut(&mut self.buf).unwrap();
|
||||
self.start.set(0);
|
||||
}
|
||||
|
||||
fn buf_mut(&mut self) -> &mut [u8] {
|
||||
// The contract here is that we NEVER have a MemSlice that exists
|
||||
// with slice.end > self.start.
|
||||
// In other words, we should *ALWAYS* be the only instance that can
|
||||
// look at the bytes on the right side of self.start.
|
||||
unsafe {
|
||||
&mut (*self.buf.get())[self.start..]
|
||||
&mut (*self.buf.get())[self.start.get()..]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +177,9 @@ fn test_grow_zerofill() {
|
||||
impl fmt::Debug for MemBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("MemBuf")
|
||||
.field("start", &self.start)
|
||||
.field("start", &self.start.get())
|
||||
.field("end", &self.end)
|
||||
.field("buf", &&self.buf()[self.start..self.end])
|
||||
.field("buf", &&self.buf()[self.start.get()..self.end])
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -182,7 +190,7 @@ impl From<Vec<u8>> for MemBuf {
|
||||
vec.shrink_to_fit();
|
||||
MemBuf {
|
||||
buf: Arc::new(UnsafeCell::new(vec)),
|
||||
start: 0,
|
||||
start: Cell::new(0),
|
||||
end: end,
|
||||
}
|
||||
}
|
||||
@@ -203,23 +211,118 @@ impl MemSlice {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.get().len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.get().is_empty()
|
||||
}
|
||||
|
||||
pub fn slice<S: Slice>(&self, range: S) -> MemSlice {
|
||||
range.slice(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Debug for MemSlice {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
fn get(&self) -> &[u8] {
|
||||
unsafe { &(*self.buf.get())[self.start..self.end] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MemSlice {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
&(*self.buf.get())[self.start..self.end]
|
||||
impl AsRef<[u8]> for MemSlice {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MemSlice {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.get(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for MemSlice {
|
||||
type Output = u8;
|
||||
fn index(&self, i: usize) -> &u8 {
|
||||
&self.get()[i]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for MemSlice {
|
||||
fn from(v: &'a [u8]) -> MemSlice {
|
||||
MemSlice {
|
||||
buf: Arc::new(UnsafeCell::new(v.to_vec())),
|
||||
start: 0,
|
||||
end: v.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for MemSlice {
|
||||
fn from(v: Vec<u8>) -> MemSlice {
|
||||
let len = v.len();
|
||||
MemSlice {
|
||||
buf: Arc::new(UnsafeCell::new(v)),
|
||||
start: 0,
|
||||
end: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for MemSlice {
|
||||
fn from(v: &'a str) -> MemSlice {
|
||||
let v = v.as_bytes();
|
||||
MemSlice {
|
||||
buf: Arc::new(UnsafeCell::new(v.to_vec())),
|
||||
start: 0,
|
||||
end: v.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Cow<'a, [u8]>> for MemSlice {
|
||||
fn from(v: Cow<'a, [u8]>) -> MemSlice {
|
||||
let v = v.into_owned();
|
||||
let len = v.len();
|
||||
MemSlice {
|
||||
buf: Arc::new(UnsafeCell::new(v)),
|
||||
start: 0,
|
||||
end: len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for MemSlice {
|
||||
fn eq(&self, other: &MemSlice) -> bool {
|
||||
self.get() == other.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<[u8]> for MemSlice {
|
||||
fn eq(&self, other: &[u8]) -> bool {
|
||||
self.get() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for MemSlice {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.get() == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Vec<u8>> for MemSlice {
|
||||
fn eq(&self, other: &Vec<u8>) -> bool {
|
||||
self.get() == other.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for MemSlice {}
|
||||
|
||||
impl Clone for MemSlice {
|
||||
fn clone(&self) -> MemSlice {
|
||||
MemSlice {
|
||||
buf: self.buf.clone(),
|
||||
start: self.start,
|
||||
end: self.end,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,18 +399,18 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_mem_slice_slice() {
|
||||
let mut buf = MemBuf::from(b"Hello World".to_vec());
|
||||
let buf = MemBuf::from(b"Hello World".to_vec());
|
||||
|
||||
let len = buf.len();
|
||||
let full = buf.slice(len);
|
||||
|
||||
assert_eq!(&*full, b"Hello World");
|
||||
assert_eq!(&*full.slice(6..), b"World");
|
||||
assert_eq!(&*full.slice(..5), b"Hello");
|
||||
assert_eq!(&*full.slice(..), b"Hello World");
|
||||
assert_eq!(full.as_ref(), b"Hello World");
|
||||
assert_eq!(full.slice(6..).as_ref(), b"World");
|
||||
assert_eq!(full.slice(..5).as_ref(), b"Hello");
|
||||
assert_eq!(full.slice(..).as_ref(), b"Hello World");
|
||||
for a in 0..len {
|
||||
for b in a..len {
|
||||
assert_eq!(&*full.slice(a..b), &b"Hello World"[a..b], "{}..{}", a, b);
|
||||
assert_eq!(full.slice(a..b).as_ref(), &b"Hello World"[a..b], "{}..{}", a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ impl AsRef<[u8]> for Chunk {
|
||||
match self.0 {
|
||||
Inner::Owned(ref vec) => vec,
|
||||
Inner::Referenced(ref vec) => vec,
|
||||
Inner::Mem(ref slice) => slice,
|
||||
Inner::Mem(ref slice) => slice.as_ref(),
|
||||
Inner::Static(slice) => slice,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,6 +595,21 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conn_parse_partial() {
|
||||
let good_message = b"GET / HTTP/1.1\r\nHost: foo.bar\r\n\r\n".to_vec();
|
||||
let io = AsyncIo::new_buf(good_message, 10);
|
||||
let mut conn = Conn::<_, ServerTransaction>::new(io, Default::default());
|
||||
assert!(conn.poll().unwrap().is_not_ready());
|
||||
conn.io.io_mut().block_in(50);
|
||||
let async = conn.poll().unwrap();
|
||||
assert!(async.is_ready());
|
||||
match async {
|
||||
Async::Ready(Some(Frame::Message { .. })) => (),
|
||||
f => panic!("frame is not Message: {:?}", f),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conn_closed_read() {
|
||||
let io = AsyncIo::new_buf(vec![], 0);
|
||||
|
||||
@@ -88,7 +88,7 @@ impl Decoder {
|
||||
} else {
|
||||
let to_read = *remaining as usize;
|
||||
let buf = try!(body.read_mem(to_read));
|
||||
let num = buf.len() as u64;
|
||||
let num = buf.as_ref().len() as u64;
|
||||
trace!("Length read: {}", num);
|
||||
if num > *remaining {
|
||||
*remaining = 0;
|
||||
@@ -399,7 +399,7 @@ mod tests {
|
||||
let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
|
||||
let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode");
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.to_vec()).expect("decode String");
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ mod tests {
|
||||
// normal read
|
||||
let buf = decoder.decode(&mut mock_buf).expect("decode");
|
||||
assert_eq!(16, buf.len());
|
||||
let result = String::from_utf8(buf.to_vec()).expect("decode String");
|
||||
let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String");
|
||||
assert_eq!("1234567890abcdef", &result);
|
||||
|
||||
// eof read
|
||||
@@ -438,7 +438,7 @@ mod tests {
|
||||
if buf.is_empty() {
|
||||
break; // eof
|
||||
}
|
||||
outs.write(&buf).expect("write buffer");
|
||||
outs.write(buf.as_ref()).expect("write buffer");
|
||||
}
|
||||
Err(e) => match e.kind() {
|
||||
io::ErrorKind::WouldBlock => {
|
||||
|
||||
@@ -6,6 +6,7 @@ use httparse;
|
||||
use header::{self, Headers, ContentLength, TransferEncoding};
|
||||
use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine};
|
||||
use http::h1::{Encoder, Decoder};
|
||||
use http::buf::{MemBuf, MemSlice};
|
||||
use method::Method;
|
||||
use status::StatusCode;
|
||||
use version::HttpVersion::{Http10, Http11};
|
||||
@@ -13,7 +14,7 @@ use version::HttpVersion::{Http10, Http11};
|
||||
const MAX_HEADERS: usize = 100;
|
||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||
|
||||
pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &[u8]) -> ParseResult<I> {
|
||||
pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &MemBuf) -> ParseResult<I> {
|
||||
if buf.len() == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -25,23 +26,29 @@ impl Http1Transaction for ServerTransaction {
|
||||
type Incoming = RequestLine;
|
||||
type Outgoing = StatusCode;
|
||||
|
||||
fn parse(buf: &[u8]) -> ParseResult<RequestLine> {
|
||||
fn parse(buf: &MemBuf) -> ParseResult<RequestLine> {
|
||||
let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
|
||||
trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len());
|
||||
let mut req = httparse::Request::new(&mut headers);
|
||||
Ok(match try!(req.parse(buf)) {
|
||||
Ok(match try!(req.parse(buf.bytes())) {
|
||||
httparse::Status::Complete(len) => {
|
||||
trace!("Request.parse Complete({})", len);
|
||||
let mut headers = Headers::with_capacity(req.headers.len());
|
||||
let slice = buf.slice(len);
|
||||
headers.extend(HeadersAsMemSliceIter {
|
||||
headers: req.headers.iter(),
|
||||
slice: slice,
|
||||
});
|
||||
Some((MessageHead {
|
||||
version: if req.version.unwrap() == 1 { Http11 } else { Http10 },
|
||||
subject: RequestLine(
|
||||
try!(req.method.unwrap().parse()),
|
||||
try!(req.path.unwrap().parse())
|
||||
),
|
||||
headers: try!(Headers::from_raw(req.headers))
|
||||
headers: headers,
|
||||
}, len))
|
||||
},
|
||||
httparse::Status::Partial => None
|
||||
}
|
||||
httparse::Status::Partial => None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -112,11 +119,11 @@ impl Http1Transaction for ClientTransaction {
|
||||
type Incoming = RawStatus;
|
||||
type Outgoing = RequestLine;
|
||||
|
||||
fn parse(buf: &[u8]) -> ParseResult<RawStatus> {
|
||||
fn parse(buf: &MemBuf) -> ParseResult<RawStatus> {
|
||||
let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
|
||||
trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len());
|
||||
let mut res = httparse::Response::new(&mut headers);
|
||||
Ok(match try!(res.parse(buf)) {
|
||||
Ok(match try!(res.parse(buf.bytes())) {
|
||||
httparse::Status::Complete(len) => {
|
||||
trace!("Response.try_parse Complete({})", len);
|
||||
let code = res.code.unwrap();
|
||||
@@ -124,10 +131,16 @@ impl Http1Transaction for ClientTransaction {
|
||||
Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason),
|
||||
_ => Cow::Owned(res.reason.unwrap().to_owned())
|
||||
};
|
||||
let mut headers = Headers::with_capacity(res.headers.len());
|
||||
let slice = buf.slice(len);
|
||||
headers.extend(HeadersAsMemSliceIter {
|
||||
headers: res.headers.iter(),
|
||||
slice: slice,
|
||||
});
|
||||
Some((MessageHead {
|
||||
version: if res.version.unwrap() == 1 { Http11 } else { Http10 },
|
||||
subject: RawStatus(code, reason),
|
||||
headers: try!(Headers::from_raw(res.headers))
|
||||
headers: headers,
|
||||
}, len))
|
||||
},
|
||||
httparse::Status::Partial => None
|
||||
@@ -216,6 +229,22 @@ impl Http1Transaction for ClientTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
struct HeadersAsMemSliceIter<'a> {
|
||||
headers: ::std::slice::Iter<'a, httparse::Header<'a>>,
|
||||
slice: MemSlice,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for HeadersAsMemSliceIter<'a> {
|
||||
type Item = (&'a str, MemSlice);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.headers.next().map(|header| {
|
||||
let value_start = header.value.as_ptr() as usize - self.slice.as_ref().as_ptr() as usize;
|
||||
let value_end = value_start + header.value.len();
|
||||
(header.name, self.slice.slice(value_start..value_end))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct FastWrite<'a>(&'a mut Vec<u8>);
|
||||
|
||||
impl<'a> fmt::Write for FastWrite<'a> {
|
||||
@@ -244,22 +273,23 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use http;
|
||||
use http::buf::MemBuf;
|
||||
use super::{parse};
|
||||
|
||||
#[test]
|
||||
fn test_parse_request() {
|
||||
let raw = b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n";
|
||||
parse::<http::ServerTransaction, _>(raw).unwrap();
|
||||
let raw = MemBuf::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
|
||||
parse::<http::ServerTransaction, _>(&raw).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_raw_status() {
|
||||
let raw = b"HTTP/1.1 200 OK\r\n\r\n";
|
||||
let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap();
|
||||
let raw = MemBuf::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec());
|
||||
let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap();
|
||||
assert_eq!(res.subject.1, "OK");
|
||||
|
||||
let raw = b"HTTP/1.1 200 Howdy\r\n\r\n";
|
||||
let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap();
|
||||
let raw = MemBuf::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec());
|
||||
let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap();
|
||||
assert_eq!(res.subject.1, "Howdy");
|
||||
}
|
||||
|
||||
@@ -269,9 +299,26 @@ mod tests {
|
||||
#[cfg(feature = "nightly")]
|
||||
#[bench]
|
||||
fn bench_parse_incoming(b: &mut Bencher) {
|
||||
let raw = b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n";
|
||||
let mut raw = MemBuf::from(b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
|
||||
I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
|
||||
_up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
|
||||
foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
|
||||
hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \
|
||||
utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\
|
||||
Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\
|
||||
Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\
|
||||
Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\
|
||||
Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\
|
||||
\r\nSec-Websocket-Extensions: It looks super important!\r\n\
|
||||
Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\
|
||||
\nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\
|
||||
X-Content-Duration: None\r\nX-Content-Security-Policy: None\
|
||||
\r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
|
||||
Something important obviously\r\nX-Requested-With: Nothing\
|
||||
\r\n\r\n".to_vec());
|
||||
b.iter(|| {
|
||||
parse::<http::ServerTransaction, _>(raw).unwrap()
|
||||
parse::<http::ServerTransaction, _>(&raw).unwrap();
|
||||
raw.restart();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -70,11 +70,11 @@ impl<T: Io> Buffered<T> {
|
||||
_ => return Err(e.into())
|
||||
}
|
||||
}
|
||||
match try!(parse::<S, _>(self.read_buf.bytes())) {
|
||||
Some((head, len)) => {
|
||||
trace!("parsed {} bytes out of {}", len, self.read_buf.len());
|
||||
self.read_buf.slice(len);
|
||||
Ok(Some(head))
|
||||
match try!(parse::<S, _>(&self.read_buf)) {
|
||||
Some(head) => {
|
||||
//trace!("parsed {} bytes out of {}", len, self.read_buf.len());
|
||||
//self.read_buf.slice(len);
|
||||
Ok(Some(head.0))
|
||||
},
|
||||
None => {
|
||||
if self.read_buf.capacity() >= MAX_BUFFER_SIZE {
|
||||
@@ -140,7 +140,7 @@ impl<T: Write> Write for Buffered<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &[u8]) -> ParseResult<I> {
|
||||
fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &MemBuf) -> ParseResult<I> {
|
||||
h1::parse::<T, I>(rdr)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@ use version::HttpVersion::{Http10, Http11};
|
||||
pub use self::conn::{Conn, KeepAlive, KA};
|
||||
pub use self::body::{Body, TokioBody};
|
||||
pub use self::chunk::Chunk;
|
||||
use self::buf::MemBuf;
|
||||
|
||||
mod body;
|
||||
mod buf;
|
||||
#[doc(hidden)]
|
||||
pub mod buf;
|
||||
mod chunk;
|
||||
mod conn;
|
||||
mod io;
|
||||
@@ -123,7 +125,7 @@ pub trait Http1Transaction {
|
||||
type Incoming;
|
||||
type Outgoing: Default;
|
||||
//type KeepAlive: KeepAlive;
|
||||
fn parse(bytes: &[u8]) -> ParseResult<Self::Incoming>;
|
||||
fn parse(bytes: &MemBuf) -> ParseResult<Self::Incoming>;
|
||||
fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>;
|
||||
fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder;
|
||||
fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool;
|
||||
|
||||
@@ -6,7 +6,8 @@ use tokio::io::Io;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Buf {
|
||||
vec: Vec<u8>
|
||||
vec: Vec<u8>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Buf {
|
||||
@@ -17,6 +18,7 @@ impl Buf {
|
||||
pub fn wrap(vec: Vec<u8>) -> Buf {
|
||||
Buf {
|
||||
vec: vec,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +50,10 @@ impl Write for Buf {
|
||||
|
||||
impl Read for Buf {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
(&*self.vec).read(buf)
|
||||
(&self.vec[self.pos..]).read(buf).map(|n| {
|
||||
self.pos += n;
|
||||
n
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user