Add ResponseBuilder::raw_body. Use OrderMap for HeaderMap.

This commit is contained in:
Sergio Benitez 2017-05-20 11:41:44 -07:00
parent 80a1abdc89
commit 6c00d362c0
6 changed files with 43 additions and 5 deletions

View File

@ -33,6 +33,7 @@ pear_codegen = "0.0.8"
rustls = { version = "0.7.0", optional = true }
cookie = { version = "0.8.1", features = ["percent-encode", "secure"] }
hyper = { version = "0.10.9", default-features = false }
ordermap = "0.2"
[dependencies.hyper-rustls]
git = "https://github.com/SergioBenitez/hyper-rustls"

View File

@ -278,6 +278,13 @@ impl fmt::Display for ContentType {
impl Into<Header<'static>> for ContentType {
#[inline(always)]
fn into(self) -> Header<'static> {
// FIXME: For known media types, don't do `to_string`. Store the whole
// string as a `source` and have a way to know that the source is
// everything. That removes the allocation here. Then, in
// `MediaType::fmt`, write the source string out directly as well.
//
// We could also use an `enum` for MediaType. But that kinda sucks. But
// maybe it's what we want.
Header::new("Content-Type", self.to_string())
}
}

View File

@ -1,7 +1,8 @@
use std::collections::HashMap;
use std::borrow::{Borrow, Cow};
use std::fmt;
use ordermap::OrderMap;
use http::uncased::{Uncased, UncasedStr};
/// Simple representation of an HTTP header.
@ -109,14 +110,14 @@ impl<'h> fmt::Display for Header<'h> {
/// A collection of headers, mapping a header name to its many ordered values.
#[derive(Clone, Debug, PartialEq, Default)]
pub struct HeaderMap<'h> {
headers: HashMap<Uncased<'h>, Vec<Cow<'h, str>>>
headers: OrderMap<Uncased<'h>, Vec<Cow<'h, str>>>
}
impl<'h> HeaderMap<'h> {
/// Returns an empty collection.
#[inline(always)]
pub fn new() -> HeaderMap<'h> {
HeaderMap { headers: HashMap::new() }
HeaderMap { headers: OrderMap::new() }
}
/// Returns true if `self` contains a header with the name `name`.
@ -134,7 +135,7 @@ impl<'h> HeaderMap<'h> {
/// ```
#[inline]
pub fn contains(&self, name: &str) -> bool {
self.headers.get(name.into() : &UncasedStr).is_some()
self.headers.get(UncasedStr::new(name)).is_some()
}
/// Returns the number of _values_ stored in the map.

View File

@ -23,6 +23,11 @@ use std::fmt;
pub struct UncasedStr(str);
impl UncasedStr {
#[inline(always)]
pub fn new(string: &str) -> &UncasedStr {
unsafe { &*(string as *const str as *const UncasedStr) }
}
#[inline(always)]
pub fn as_str(&self) -> &str {
&self.0
@ -67,7 +72,7 @@ impl<'a> PartialEq<UncasedStr> for &'a str {
impl<'a> From<&'a str> for &'a UncasedStr {
#[inline(always)]
fn from(string: &'a str) -> &'a UncasedStr {
unsafe { ::std::mem::transmute(string) }
UncasedStr::new(string)
}
}

View File

@ -113,6 +113,7 @@ extern crate time;
extern crate memchr;
extern crate base64;
extern crate smallvec;
extern crate ordermap;
#[cfg(test)] #[macro_use] extern crate lazy_static;

View File

@ -415,6 +415,29 @@ impl<'r> ResponseBuilder<'r> {
self
}
/// Sets the body of `self` to be `body`. This method should typically not
/// be used, opting instead for one of `sized_body`, `streamed_body`, or
/// `chunked_body`.
///
/// # Example
///
/// ```rust
/// use std::io::Cursor;
/// use rocket::response::{Response, Body};
///
/// # #[allow(unused_variables)]
/// let response = Response::build()
/// .raw_body(Body::Sized(Cursor::new("Hello!"), 6))
/// .finalize();
/// ```
#[inline(always)]
pub fn raw_body<T: io::Read + 'r>(&mut self, body: Body<T>)
-> &mut ResponseBuilder<'r>
{
self.response.set_raw_body(body);
self
}
/// Merges the `other` `Response` into `self` by setting any fields in
/// `self` to the corresponding value in `other` if they are set in `other`.
/// Fields in `self` are unchanged if they are not set in `other`. If a