mirror of https://github.com/rwf2/Rocket.git
Optimize the creation of the Data structure.
This commit is contained in:
parent
423acdd32a
commit
40d11929d7
|
@ -18,10 +18,10 @@ pub type HyperBodyReader<'a, 'b> =
|
||||||
self::HttpReader<&'a mut hyper::buffer::BufReader<&'b mut NetworkStream>>;
|
self::HttpReader<&'a mut hyper::buffer::BufReader<&'b mut NetworkStream>>;
|
||||||
|
|
||||||
// |---- from hyper ----|
|
// |---- from hyper ----|
|
||||||
pub type BodyReader = HttpReader<Chain<Take<Cursor<Vec<u8>>>, BufReader<NetStream>>>;
|
pub type BodyReader = HttpReader<Chain<Cursor<Vec<u8>>, NetStream>>;
|
||||||
|
|
||||||
/// The number of bytes to read into the "peek" buffer.
|
/// The number of bytes to read into the "peek" buffer.
|
||||||
const PEEK_BYTES: usize = 4096;
|
const PEEK_BYTES: usize = 512;
|
||||||
|
|
||||||
/// Type representing the data in the body of an incoming request.
|
/// Type representing the data in the body of an incoming request.
|
||||||
///
|
///
|
||||||
|
@ -48,7 +48,7 @@ const PEEK_BYTES: usize = 4096;
|
||||||
/// object ensures that holding a `Data` object means that all of the data is
|
/// object ensures that holding a `Data` object means that all of the data is
|
||||||
/// available for reading.
|
/// available for reading.
|
||||||
///
|
///
|
||||||
/// The `peek` method returns a slice containing at most 4096 bytes of buffered
|
/// The `peek` method returns a slice containing at most 512 bytes of buffered
|
||||||
/// body data. This enables partially or fully reading from a `Data` object
|
/// body data. This enables partially or fully reading from a `Data` object
|
||||||
/// without consuming the `Data` object.
|
/// without consuming the `Data` object.
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
|
@ -66,9 +66,12 @@ impl Data {
|
||||||
/// the data in a request.
|
/// the data in a request.
|
||||||
pub fn open(mut self) -> DataStream {
|
pub fn open(mut self) -> DataStream {
|
||||||
let buffer = ::std::mem::replace(&mut self.buffer, vec![]);
|
let buffer = ::std::mem::replace(&mut self.buffer, vec![]);
|
||||||
let empty_stream = Cursor::new(vec![]).take(0)
|
let empty_stream = Cursor::new(vec![])
|
||||||
.chain(BufReader::new(NetStream::Local(Cursor::new(vec![]))));
|
.chain(NetStream::Local(Cursor::new(vec![])));
|
||||||
|
|
||||||
|
// FIXME: Insert a `BufReader` in front of the `NetStream` with capacity
|
||||||
|
// 4096. We need the new `Chain` methods to get the inner reader to
|
||||||
|
// actually do this, however.
|
||||||
let empty_http_stream = HttpReader::SizedReader(empty_stream, 0);
|
let empty_http_stream = HttpReader::SizedReader(empty_stream, 0);
|
||||||
let stream = ::std::mem::replace(&mut self.stream, empty_http_stream);
|
let stream = ::std::mem::replace(&mut self.stream, empty_http_stream);
|
||||||
DataStream(Cursor::new(buffer).chain(stream))
|
DataStream(Cursor::new(buffer).chain(stream))
|
||||||
|
@ -77,10 +80,12 @@ impl Data {
|
||||||
// FIXME: This is absolutely terrible (downcasting!), thanks to Hyper.
|
// FIXME: This is absolutely terrible (downcasting!), thanks to Hyper.
|
||||||
pub(crate) fn from_hyp(mut body: HyperBodyReader) -> Result<Data, &'static str> {
|
pub(crate) fn from_hyp(mut body: HyperBodyReader) -> Result<Data, &'static str> {
|
||||||
// Steal the internal, undecoded data buffer and net stream from Hyper.
|
// Steal the internal, undecoded data buffer and net stream from Hyper.
|
||||||
let (hyper_buf, pos, cap) = body.get_mut().take_buf();
|
let (mut hyper_buf, pos, cap) = body.get_mut().take_buf();
|
||||||
|
unsafe { hyper_buf.set_len(cap); }
|
||||||
let hyper_net_stream = body.get_ref().get_ref();
|
let hyper_net_stream = body.get_ref().get_ref();
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
|
#[inline(always)]
|
||||||
fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> {
|
fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> {
|
||||||
stream.downcast_ref::<HttpsStream>()
|
stream.downcast_ref::<HttpsStream>()
|
||||||
.map(|s| NetStream::Https(s.clone()))
|
.map(|s| NetStream::Https(s.clone()))
|
||||||
|
@ -91,6 +96,7 @@ impl Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "tls"))]
|
||||||
|
#[inline(always)]
|
||||||
fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> {
|
fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> {
|
||||||
stream.downcast_ref::<HttpStream>()
|
stream.downcast_ref::<HttpStream>()
|
||||||
.map(|s| NetStream::Http(s.clone()))
|
.map(|s| NetStream::Http(s.clone()))
|
||||||
|
@ -107,11 +113,10 @@ impl Data {
|
||||||
|
|
||||||
// TODO: Explain this.
|
// TODO: Explain this.
|
||||||
trace_!("Hyper buffer: [{}..{}] ({} bytes).", pos, cap, cap - pos);
|
trace_!("Hyper buffer: [{}..{}] ({} bytes).", pos, cap, cap - pos);
|
||||||
let (start, remaining) = (pos as u64, (cap - pos) as u64);
|
|
||||||
let mut cursor = Cursor::new(hyper_buf);
|
let mut cursor = Cursor::new(hyper_buf);
|
||||||
cursor.set_position(start);
|
cursor.set_position(pos as u64);
|
||||||
let inner_data = cursor.take(remaining)
|
let inner_data = cursor.chain(net_stream);
|
||||||
.chain(BufReader::new(net_stream.clone()));
|
|
||||||
|
|
||||||
// Create an HTTP reader from the stream.
|
// Create an HTTP reader from the stream.
|
||||||
let http_stream = match body {
|
let http_stream = match body {
|
||||||
|
@ -132,8 +137,12 @@ impl Data {
|
||||||
/// buffer contains _all_ of the data in the body of the request.
|
/// buffer contains _all_ of the data in the body of the request.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn peek(&self) -> &[u8] {
|
pub fn peek(&self) -> &[u8] {
|
||||||
|
if self.buffer.len() > PEEK_BYTES {
|
||||||
|
&self.buffer[..PEEK_BYTES]
|
||||||
|
} else {
|
||||||
&self.buffer
|
&self.buffer
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the `peek` buffer contains all of the data in the body
|
/// Returns true if the `peek` buffer contains all of the data in the body
|
||||||
/// of the request. Returns `false` if it does not or if it is not known if
|
/// of the request. Returns `false` if it does not or if it is not known if
|
||||||
|
@ -165,6 +174,7 @@ impl Data {
|
||||||
// in the buffer is at `pos` and the buffer has `cap` valid bytes. Thus, the
|
// in the buffer is at `pos` and the buffer has `cap` valid bytes. Thus, the
|
||||||
// bytes `vec[pos..cap]` are buffered and unread. The remainder of the data
|
// bytes `vec[pos..cap]` are buffered and unread. The remainder of the data
|
||||||
// bytes can be read from `stream`.
|
// bytes can be read from `stream`.
|
||||||
|
#[inline(always)]
|
||||||
pub(crate) fn new(mut stream: BodyReader) -> Data {
|
pub(crate) fn new(mut stream: BodyReader) -> Data {
|
||||||
trace_!("Date::new({:?})", stream);
|
trace_!("Date::new({:?})", stream);
|
||||||
let mut peek_buf = vec![0; PEEK_BYTES];
|
let mut peek_buf = vec![0; PEEK_BYTES];
|
||||||
|
@ -196,22 +206,13 @@ impl Data {
|
||||||
|
|
||||||
/// This creates a `data` object from a local data source `data`.
|
/// This creates a `data` object from a local data source `data`.
|
||||||
pub(crate) fn local(mut data: Vec<u8>) -> Data {
|
pub(crate) fn local(mut data: Vec<u8>) -> Data {
|
||||||
// Emulate peek buffering.
|
let empty_stream = Cursor::new(vec![])
|
||||||
let (buf, rest) = if data.len() <= PEEK_BYTES {
|
.chain(NetStream::Local(Cursor::new(vec![])));
|
||||||
(data, vec![])
|
|
||||||
} else {
|
|
||||||
let rest = data.split_off(PEEK_BYTES);
|
|
||||||
(data, rest)
|
|
||||||
};
|
|
||||||
|
|
||||||
let stream_len = rest.len() as u64;
|
|
||||||
let stream = Cursor::new(vec![]).take(0)
|
|
||||||
.chain(BufReader::new(NetStream::Local(Cursor::new(rest))));
|
|
||||||
|
|
||||||
Data {
|
Data {
|
||||||
buffer: buf,
|
buffer: data,
|
||||||
stream: HttpReader::SizedReader(stream, stream_len),
|
stream: HttpReader::SizedReader(empty_stream, 0),
|
||||||
is_complete: stream_len == 0,
|
is_complete: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,7 @@ impl Rocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn write_response(&self, mut response: Response,
|
fn write_response(&self, mut response: Response,
|
||||||
mut hyp_res: hyper::FreshResponse) -> io::Result<()>
|
mut hyp_res: hyper::FreshResponse) -> io::Result<()>
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,8 @@ pub trait Collider<T: ?Sized = Self> {
|
||||||
fn collides_with(&self, other: &T) -> bool;
|
fn collides_with(&self, other: &T) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index_match_until(break_c: char,
|
#[inline(always)]
|
||||||
|
fn index_match_until(break_c: char,
|
||||||
a: &str,
|
a: &str,
|
||||||
b: &str,
|
b: &str,
|
||||||
dir: bool)
|
dir: bool)
|
||||||
|
@ -39,11 +40,13 @@ pub fn index_match_until(break_c: char,
|
||||||
Some((i, j))
|
Some((i, j))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn do_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool {
|
fn do_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool {
|
||||||
index_match_until(break_c, a, b, dir).is_some()
|
index_match_until(break_c, a, b, dir).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Collider<str> for &'a str {
|
impl<'a> Collider<str> for &'a str {
|
||||||
|
#[inline(always)]
|
||||||
fn collides_with(&self, other: &str) -> bool {
|
fn collides_with(&self, other: &str) -> bool {
|
||||||
let (a, b) = (self, other);
|
let (a, b) = (self, other);
|
||||||
do_match_until('<', a, b, true) && do_match_until('>', a, b, false)
|
do_match_until('<', a, b, true) && do_match_until('>', a, b, false)
|
||||||
|
@ -72,6 +75,7 @@ impl<'a, 'b> Collider<URI<'b>> for URI<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collider for MediaType {
|
impl Collider for MediaType {
|
||||||
|
#[inline(always)]
|
||||||
fn collides_with(&self, other: &MediaType) -> bool {
|
fn collides_with(&self, other: &MediaType) -> bool {
|
||||||
let collide = |a, b| a == "*" || b == "*" || a == b;
|
let collide = |a, b| a == "*" || b == "*" || a == b;
|
||||||
collide(self.top(), other.top()) && collide(self.sub(), other.sub())
|
collide(self.top(), other.top()) && collide(self.sub(), other.sub())
|
||||||
|
@ -113,10 +117,9 @@ impl<'r> Collider<Request<'r>> for Route {
|
||||||
self.method == req.method()
|
self.method == req.method()
|
||||||
&& self.path.collides_with(req.uri())
|
&& self.path.collides_with(req.uri())
|
||||||
&& self.path.query().map_or(true, |_| req.uri().query().is_some())
|
&& self.path.query().map_or(true, |_| req.uri().query().is_some())
|
||||||
// FIXME: Avoid calling `format` is `self.format` == None.
|
&& match self.format {
|
||||||
&& match self.format.as_ref() {
|
Some(ref mt_a) => match req.format() {
|
||||||
Some(mt_a) => match req.format().as_ref() {
|
Some(ref mt_b) => mt_a.collides_with(mt_b),
|
||||||
Some(mt_b) => mt_a.collides_with(mt_b),
|
|
||||||
None => false
|
None => false
|
||||||
},
|
},
|
||||||
None => true
|
None => true
|
||||||
|
|
Loading…
Reference in New Issue