mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-27 17:22:57 +01:00
split http request; add HttpRequest::range()
This commit is contained in:
parent
f30aef404d
commit
41f1e6cdc9
@ -30,10 +30,13 @@ nightly = []
|
|||||||
time = "0.1"
|
time = "0.1"
|
||||||
http = "0.1"
|
http = "0.1"
|
||||||
httparse = "0.1"
|
httparse = "0.1"
|
||||||
|
http-range = "0.1"
|
||||||
cookie = { version="0.10", features=["percent-encode"] }
|
cookie = { version="0.10", features=["percent-encode"] }
|
||||||
|
regex = "0.2"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
sha1 = "0.2"
|
sha1 = "0.2"
|
||||||
url = "1.5"
|
url = "1.5"
|
||||||
|
lazy_static = "0.2"
|
||||||
route-recognizer = "0.1"
|
route-recognizer = "0.1"
|
||||||
|
|
||||||
# tokio
|
# tokio
|
||||||
|
@ -9,7 +9,7 @@ use route::RouteHandler;
|
|||||||
use router::Handler;
|
use router::Handler;
|
||||||
use resource::Resource;
|
use resource::Resource;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httpmessage::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
|
|
||||||
|
|
||||||
/// Application
|
/// Application
|
||||||
|
16
src/dev.rs
16
src/dev.rs
@ -9,13 +9,23 @@
|
|||||||
//! ```
|
//! ```
|
||||||
pub use ws;
|
pub use ws;
|
||||||
pub use httpcodes;
|
pub use httpcodes;
|
||||||
|
pub use error::ParseError;
|
||||||
pub use application::Application;
|
pub use application::Application;
|
||||||
pub use httpmessage::{Body, Builder, HttpRequest, HttpResponse};
|
pub use httprequest::HttpRequest;
|
||||||
pub use payload::{Payload, PayloadItem};
|
pub use httpmessage::{Body, Builder, HttpResponse};
|
||||||
|
pub use payload::{Payload, PayloadItem, PayloadError};
|
||||||
pub use router::RoutingMap;
|
pub use router::RoutingMap;
|
||||||
pub use resource::{Reply, Resource};
|
pub use resource::{Reply, Resource};
|
||||||
pub use route::{Route, RouteFactory, RouteHandler};
|
pub use route::{Route, RouteFactory, RouteHandler};
|
||||||
pub use server::HttpServer;
|
pub use server::HttpServer;
|
||||||
pub use context::HttpContext;
|
pub use context::HttpContext;
|
||||||
pub use task::Task;
|
pub use staticfiles::StaticFiles;
|
||||||
|
|
||||||
|
// re-exports
|
||||||
|
pub use cookie::{Cookie, CookieBuilder};
|
||||||
|
pub use cookie::{ParseError as CookieParseError};
|
||||||
pub use route_recognizer::Params;
|
pub use route_recognizer::Params;
|
||||||
|
pub use http_range::{HttpRange, HttpRangeParseError};
|
||||||
|
|
||||||
|
// dev specific
|
||||||
|
pub use task::Task;
|
||||||
|
10
src/error.rs
10
src/error.rs
@ -9,8 +9,10 @@ use cookie;
|
|||||||
use httparse;
|
use httparse;
|
||||||
use http::{StatusCode, Error as HttpError};
|
use http::{StatusCode, Error as HttpError};
|
||||||
|
|
||||||
|
use HttpRangeParseError;
|
||||||
use httpmessage::{Body, HttpResponse};
|
use httpmessage::{Body, HttpResponse};
|
||||||
|
|
||||||
|
|
||||||
/// A set of errors that can occur during parsing HTTP streams.
|
/// A set of errors that can occur during parsing HTTP streams.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
@ -129,6 +131,14 @@ impl From<cookie::ParseError> for HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `BadRequest` for `HttpRangeParseError`
|
||||||
|
impl From<HttpRangeParseError> for HttpResponse {
|
||||||
|
fn from(_: HttpRangeParseError) -> Self {
|
||||||
|
HttpResponse::new(StatusCode::BAD_REQUEST,
|
||||||
|
Body::Binary("Invalid Range header provided".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
|
@ -6,13 +6,15 @@ use http::StatusCode;
|
|||||||
use task::Task;
|
use task::Task;
|
||||||
use route::RouteHandler;
|
use route::RouteHandler;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httpmessage::{Body, Builder, HttpRequest, HttpResponse};
|
use httprequest::HttpRequest;
|
||||||
|
use httpmessage::{Body, Builder, HttpResponse};
|
||||||
|
|
||||||
pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK);
|
pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK);
|
||||||
pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
|
pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
|
||||||
pub const HTTPNoContent: StaticResponse = StaticResponse(StatusCode::NO_CONTENT);
|
pub const HTTPNoContent: StaticResponse = StaticResponse(StatusCode::NO_CONTENT);
|
||||||
pub const HTTPBadRequest: StaticResponse = StaticResponse(StatusCode::BAD_REQUEST);
|
pub const HTTPBadRequest: StaticResponse = StaticResponse(StatusCode::BAD_REQUEST);
|
||||||
pub const HTTPNotFound: StaticResponse = StaticResponse(StatusCode::NOT_FOUND);
|
pub const HTTPNotFound: StaticResponse = StaticResponse(StatusCode::NOT_FOUND);
|
||||||
|
pub const HTTPForbidden: StaticResponse = StaticResponse(StatusCode::FORBIDDEN);
|
||||||
pub const HTTPMethodNotAllowed: StaticResponse = StaticResponse(StatusCode::METHOD_NOT_ALLOWED);
|
pub const HTTPMethodNotAllowed: StaticResponse = StaticResponse(StatusCode::METHOD_NOT_ALLOWED);
|
||||||
pub const HTTPInternalServerError: StaticResponse =
|
pub const HTTPInternalServerError: StaticResponse =
|
||||||
StaticResponse(StatusCode::INTERNAL_SERVER_ERROR);
|
StaticResponse(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
@ -4,177 +4,23 @@ use std::convert::Into;
|
|||||||
|
|
||||||
use cookie::CookieJar;
|
use cookie::CookieJar;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use http::{Method, StatusCode, Version, Uri, HeaderMap, HttpTryFrom, Error};
|
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error};
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
|
||||||
use Params;
|
use Cookie;
|
||||||
use {Cookie, CookieParseError};
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents various types of connection
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum ConnectionType {
|
pub enum ConnectionType {
|
||||||
|
/// Close connection after response
|
||||||
Close,
|
Close,
|
||||||
|
/// Keep connection alive after response
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
|
/// Connection is upgraded to different type
|
||||||
Upgrade,
|
Upgrade,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// An HTTP Request
|
|
||||||
pub struct HttpRequest {
|
|
||||||
version: Version,
|
|
||||||
method: Method,
|
|
||||||
uri: Uri,
|
|
||||||
headers: HeaderMap,
|
|
||||||
params: Params,
|
|
||||||
cookies: Vec<Cookie<'static>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HttpRequest {
|
|
||||||
/// Construct a new Request.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(method: Method, uri: Uri, version: Version, headers: HeaderMap) -> Self {
|
|
||||||
HttpRequest {
|
|
||||||
method: method,
|
|
||||||
uri: uri,
|
|
||||||
version: version,
|
|
||||||
headers: headers,
|
|
||||||
params: Params::new(),
|
|
||||||
cookies: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read the Request Uri.
|
|
||||||
#[inline]
|
|
||||||
pub fn uri(&self) -> &Uri { &self.uri }
|
|
||||||
|
|
||||||
/// Read the Request method.
|
|
||||||
#[inline]
|
|
||||||
pub fn method(&self) -> &Method { &self.method }
|
|
||||||
|
|
||||||
/// Read the Request Version.
|
|
||||||
pub fn version(&self) -> Version {
|
|
||||||
self.version
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read the Request Headers.
|
|
||||||
pub fn headers(&self) -> &HeaderMap {
|
|
||||||
&self.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
// /// The remote socket address of this request
|
|
||||||
// ///
|
|
||||||
// /// This is an `Option`, because some underlying transports may not have
|
|
||||||
// /// a socket address, such as Unix Sockets.
|
|
||||||
// ///
|
|
||||||
// /// This field is not used for outgoing requests.
|
|
||||||
// #[inline]
|
|
||||||
// pub fn remote_addr(&self) -> Option<SocketAddr> { self.remote_addr }
|
|
||||||
|
|
||||||
/// The target path of this Request.
|
|
||||||
#[inline]
|
|
||||||
pub fn path(&self) -> &str {
|
|
||||||
self.uri.path()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The query string of this Request.
|
|
||||||
#[inline]
|
|
||||||
pub fn query(&self) -> Option<&str> {
|
|
||||||
self.uri.query()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return request cookies.
|
|
||||||
pub fn cookies(&self) -> &Vec<Cookie<'static>> {
|
|
||||||
&self.cookies
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return request cookie.
|
|
||||||
pub fn cookie(&self, name: &str) -> Option<&Cookie> {
|
|
||||||
for cookie in &self.cookies {
|
|
||||||
if cookie.name() == name {
|
|
||||||
return Some(&cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load cookies
|
|
||||||
pub fn load_cookies(&mut self) -> Result<&Vec<Cookie>, CookieParseError>
|
|
||||||
{
|
|
||||||
if let Some(val) = self.headers.get(header::COOKIE) {
|
|
||||||
let s = str::from_utf8(val.as_bytes())
|
|
||||||
.map_err(CookieParseError::from)?;
|
|
||||||
for cookie in s.split("; ") {
|
|
||||||
self.cookies.push(Cookie::parse_encoded(cookie)?.into_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(&self.cookies)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a mutable reference to the Request headers.
|
|
||||||
#[inline]
|
|
||||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
|
||||||
&mut self.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a reference to the Params object.
|
|
||||||
/// Params is a container for url parameters.
|
|
||||||
/// Route supports glob patterns: * for a single wildcard segment and :param
|
|
||||||
/// for matching storing that segment of the request url in the Params object.
|
|
||||||
#[inline]
|
|
||||||
pub fn params(&self) -> &Params { &self.params }
|
|
||||||
|
|
||||||
/// Create new request with Params object.
|
|
||||||
pub fn with_params(self, params: Params) -> Self {
|
|
||||||
HttpRequest {
|
|
||||||
method: self.method,
|
|
||||||
uri: self.uri,
|
|
||||||
version: self.version,
|
|
||||||
headers: self.headers,
|
|
||||||
params: params,
|
|
||||||
cookies: self.cookies,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a connection should be kept alive.
|
|
||||||
pub fn keep_alive(&self) -> bool {
|
|
||||||
if let Some(conn) = self.headers.get(header::CONNECTION) {
|
|
||||||
if let Ok(conn) = conn.to_str() {
|
|
||||||
if self.version == Version::HTTP_10 && conn.contains("keep-alive") {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
self.version == Version::HTTP_11 &&
|
|
||||||
!(conn.contains("close") || conn.contains("upgrade"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.version != Version::HTTP_10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn upgrade(&self) -> bool {
|
|
||||||
if let Some(conn) = self.headers().get(header::CONNECTION) {
|
|
||||||
if let Ok(s) = conn.to_str() {
|
|
||||||
return s.to_lowercase().contains("upgrade")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.method == Method::CONNECT
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn chunked(&self) -> Result<bool, io::Error> {
|
|
||||||
if let Some(encodings) = self.headers().get(header::TRANSFER_ENCODING) {
|
|
||||||
if let Ok(s) = encodings.to_str() {
|
|
||||||
Ok(s.to_lowercase().contains("chunked"))
|
|
||||||
} else {
|
|
||||||
Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other, "Can not read transfer-encoding header"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents various types of http message body.
|
/// Represents various types of http message body.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Body {
|
pub enum Body {
|
||||||
|
178
src/httprequest.rs
Normal file
178
src/httprequest.rs
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
//! Pieces pertaining to the HTTP message protocol.
|
||||||
|
use std::{io, str};
|
||||||
|
use http::{header, Method, Version, Uri, HeaderMap};
|
||||||
|
|
||||||
|
use Params;
|
||||||
|
use {Cookie, CookieParseError};
|
||||||
|
use {HttpRange, HttpRangeParseError};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// An HTTP Request
|
||||||
|
pub struct HttpRequest {
|
||||||
|
version: Version,
|
||||||
|
method: Method,
|
||||||
|
uri: Uri,
|
||||||
|
headers: HeaderMap,
|
||||||
|
params: Params,
|
||||||
|
cookies: Vec<Cookie<'static>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HttpRequest {
|
||||||
|
/// Construct a new Request.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(method: Method, uri: Uri, version: Version, headers: HeaderMap) -> Self {
|
||||||
|
HttpRequest {
|
||||||
|
method: method,
|
||||||
|
uri: uri,
|
||||||
|
version: version,
|
||||||
|
headers: headers,
|
||||||
|
params: Params::new(),
|
||||||
|
cookies: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the Request Uri.
|
||||||
|
#[inline]
|
||||||
|
pub fn uri(&self) -> &Uri { &self.uri }
|
||||||
|
|
||||||
|
/// Read the Request method.
|
||||||
|
#[inline]
|
||||||
|
pub fn method(&self) -> &Method { &self.method }
|
||||||
|
|
||||||
|
/// Read the Request Version.
|
||||||
|
pub fn version(&self) -> Version {
|
||||||
|
self.version
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the Request Headers.
|
||||||
|
pub fn headers(&self) -> &HeaderMap {
|
||||||
|
&self.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// The remote socket address of this request
|
||||||
|
// ///
|
||||||
|
// /// This is an `Option`, because some underlying transports may not have
|
||||||
|
// /// a socket address, such as Unix Sockets.
|
||||||
|
// ///
|
||||||
|
// /// This field is not used for outgoing requests.
|
||||||
|
// #[inline]
|
||||||
|
// pub fn remote_addr(&self) -> Option<SocketAddr> { self.remote_addr }
|
||||||
|
|
||||||
|
/// The target path of this Request.
|
||||||
|
#[inline]
|
||||||
|
pub fn path(&self) -> &str {
|
||||||
|
self.uri.path()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The query string of this Request.
|
||||||
|
#[inline]
|
||||||
|
pub fn query(&self) -> Option<&str> {
|
||||||
|
self.uri.query()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return request cookies.
|
||||||
|
pub fn cookies(&self) -> &Vec<Cookie<'static>> {
|
||||||
|
&self.cookies
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return request cookie.
|
||||||
|
pub fn cookie(&self, name: &str) -> Option<&Cookie> {
|
||||||
|
for cookie in &self.cookies {
|
||||||
|
if cookie.name() == name {
|
||||||
|
return Some(&cookie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load cookies
|
||||||
|
pub fn load_cookies(&mut self) -> Result<&Vec<Cookie>, CookieParseError>
|
||||||
|
{
|
||||||
|
if let Some(val) = self.headers.get(header::COOKIE) {
|
||||||
|
let s = str::from_utf8(val.as_bytes())
|
||||||
|
.map_err(CookieParseError::from)?;
|
||||||
|
for cookie in s.split("; ") {
|
||||||
|
self.cookies.push(Cookie::parse_encoded(cookie)?.into_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(&self.cookies)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the Request headers.
|
||||||
|
#[inline]
|
||||||
|
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||||
|
&mut self.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the Params object.
|
||||||
|
/// Params is a container for url parameters.
|
||||||
|
/// Route supports glob patterns: * for a single wildcard segment and :param
|
||||||
|
/// for matching storing that segment of the request url in the Params object.
|
||||||
|
#[inline]
|
||||||
|
pub fn params(&self) -> &Params { &self.params }
|
||||||
|
|
||||||
|
/// Create new request with Params object.
|
||||||
|
pub fn with_params(self, params: Params) -> Self {
|
||||||
|
HttpRequest {
|
||||||
|
method: self.method,
|
||||||
|
uri: self.uri,
|
||||||
|
version: self.version,
|
||||||
|
headers: self.headers,
|
||||||
|
params: params,
|
||||||
|
cookies: self.cookies,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a connection should be kept alive.
|
||||||
|
pub fn keep_alive(&self) -> bool {
|
||||||
|
if let Some(conn) = self.headers.get(header::CONNECTION) {
|
||||||
|
if let Ok(conn) = conn.to_str() {
|
||||||
|
if self.version == Version::HTTP_10 && conn.contains("keep-alive") {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.version == Version::HTTP_11 &&
|
||||||
|
!(conn.contains("close") || conn.contains("upgrade"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.version != Version::HTTP_10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if request requires connection upgrade
|
||||||
|
pub(crate) fn upgrade(&self) -> bool {
|
||||||
|
if let Some(conn) = self.headers().get(header::CONNECTION) {
|
||||||
|
if let Ok(s) = conn.to_str() {
|
||||||
|
return s.to_lowercase().contains("upgrade")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.method == Method::CONNECT
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if request has chunked transfer encoding
|
||||||
|
pub fn chunked(&self) -> Result<bool, io::Error> {
|
||||||
|
if let Some(encodings) = self.headers().get(header::TRANSFER_ENCODING) {
|
||||||
|
if let Ok(s) = encodings.to_str() {
|
||||||
|
Ok(s.to_lowercase().contains("chunked"))
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other, "Can not read transfer-encoding header"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses Range HTTP header string as per RFC 2616.
|
||||||
|
/// `size` is full size of response (file).
|
||||||
|
pub fn range(&self, size: u64) -> Result<Vec<HttpRange>, HttpRangeParseError> {
|
||||||
|
if let Some(range) = self.headers().get(header::RANGE) {
|
||||||
|
HttpRange::parse(unsafe{str::from_utf8_unchecked(range.as_bytes())}, size)
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/lib.rs
16
src/lib.rs
@ -9,17 +9,21 @@ extern crate log;
|
|||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate bytes;
|
extern crate bytes;
|
||||||
extern crate sha1;
|
extern crate sha1;
|
||||||
extern crate url;
|
extern crate regex;
|
||||||
extern crate cookie;
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate tokio_core;
|
extern crate tokio_core;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
extern crate tokio_proto;
|
extern crate tokio_proto;
|
||||||
|
|
||||||
|
extern crate cookie;
|
||||||
extern crate http;
|
extern crate http;
|
||||||
extern crate httparse;
|
extern crate httparse;
|
||||||
|
extern crate http_range;
|
||||||
extern crate route_recognizer;
|
extern crate route_recognizer;
|
||||||
|
extern crate url;
|
||||||
extern crate actix;
|
extern crate actix;
|
||||||
|
|
||||||
mod application;
|
mod application;
|
||||||
@ -27,6 +31,7 @@ mod context;
|
|||||||
mod error;
|
mod error;
|
||||||
mod date;
|
mod date;
|
||||||
mod decode;
|
mod decode;
|
||||||
|
mod httprequest;
|
||||||
mod httpmessage;
|
mod httpmessage;
|
||||||
mod payload;
|
mod payload;
|
||||||
mod resource;
|
mod resource;
|
||||||
@ -34,6 +39,7 @@ mod route;
|
|||||||
mod router;
|
mod router;
|
||||||
mod task;
|
mod task;
|
||||||
mod reader;
|
mod reader;
|
||||||
|
mod staticfiles;
|
||||||
mod server;
|
mod server;
|
||||||
mod wsframe;
|
mod wsframe;
|
||||||
mod wsproto;
|
mod wsproto;
|
||||||
@ -41,16 +47,20 @@ mod wsproto;
|
|||||||
pub mod ws;
|
pub mod ws;
|
||||||
pub mod dev;
|
pub mod dev;
|
||||||
pub mod httpcodes;
|
pub mod httpcodes;
|
||||||
|
pub use error::ParseError;
|
||||||
pub use application::Application;
|
pub use application::Application;
|
||||||
pub use httpmessage::{Body, Builder, HttpRequest, HttpResponse};
|
pub use httprequest::HttpRequest;
|
||||||
|
pub use httpmessage::{Body, Builder, HttpResponse};
|
||||||
pub use payload::{Payload, PayloadItem, PayloadError};
|
pub use payload::{Payload, PayloadItem, PayloadError};
|
||||||
pub use router::RoutingMap;
|
pub use router::RoutingMap;
|
||||||
pub use resource::{Reply, Resource};
|
pub use resource::{Reply, Resource};
|
||||||
pub use route::{Route, RouteFactory, RouteHandler};
|
pub use route::{Route, RouteFactory, RouteHandler};
|
||||||
pub use server::HttpServer;
|
pub use server::HttpServer;
|
||||||
pub use context::HttpContext;
|
pub use context::HttpContext;
|
||||||
|
pub use staticfiles::StaticFiles;
|
||||||
|
|
||||||
// re-exports
|
// re-exports
|
||||||
pub use cookie::{Cookie, CookieBuilder};
|
pub use cookie::{Cookie, CookieBuilder};
|
||||||
pub use cookie::{ParseError as CookieParseError};
|
pub use cookie::{ParseError as CookieParseError};
|
||||||
pub use route_recognizer::Params;
|
pub use route_recognizer::Params;
|
||||||
|
pub use http_range::{HttpRange, HttpRangeParseError};
|
||||||
|
@ -9,7 +9,7 @@ use tokio_io::AsyncRead;
|
|||||||
|
|
||||||
use error::ParseError;
|
use error::ParseError;
|
||||||
use decode::Decoder;
|
use decode::Decoder;
|
||||||
use httpmessage::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use payload::{Payload, PayloadError, PayloadSender};
|
use payload::{Payload, PayloadError, PayloadSender};
|
||||||
|
|
||||||
const MAX_HEADERS: usize = 100;
|
const MAX_HEADERS: usize = 100;
|
||||||
|
@ -10,8 +10,9 @@ use task::Task;
|
|||||||
use route::{Route, RouteHandler};
|
use route::{Route, RouteHandler};
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use context::HttpContext;
|
use context::HttpContext;
|
||||||
|
use httprequest::HttpRequest;
|
||||||
|
use httpmessage::HttpResponse;
|
||||||
use httpcodes::HTTPMethodNotAllowed;
|
use httpcodes::HTTPMethodNotAllowed;
|
||||||
use httpmessage::{HttpRequest, HttpResponse};
|
|
||||||
|
|
||||||
/// Http resource
|
/// Http resource
|
||||||
///
|
///
|
||||||
@ -27,9 +28,8 @@ use httpmessage::{HttpRequest, HttpResponse};
|
|||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut routes = RoutingMap::default();
|
/// let mut routes = RoutingMap::default();
|
||||||
///
|
///
|
||||||
/// routes
|
/// routes.add_resource("/")
|
||||||
/// .add_resource("/")
|
/// .post::<MyRoute>();
|
||||||
/// .post::<MyRoute>();
|
|
||||||
/// }
|
/// }
|
||||||
pub struct Resource<S=()> {
|
pub struct Resource<S=()> {
|
||||||
state: PhantomData<S>,
|
state: PhantomData<S>,
|
||||||
|
@ -8,7 +8,8 @@ use task::Task;
|
|||||||
use context::HttpContext;
|
use context::HttpContext;
|
||||||
use resource::Reply;
|
use resource::Reply;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httpmessage::{HttpRequest, HttpResponse};
|
use httprequest::HttpRequest;
|
||||||
|
use httpmessage::HttpResponse;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -9,7 +9,7 @@ use route::RouteHandler;
|
|||||||
use resource::Resource;
|
use resource::Resource;
|
||||||
use application::Application;
|
use application::Application;
|
||||||
use httpcodes::HTTPNotFound;
|
use httpcodes::HTTPNotFound;
|
||||||
use httpmessage::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
|
|
||||||
pub(crate) trait Handler: 'static {
|
pub(crate) trait Handler: 'static {
|
||||||
fn handle(&self, req: HttpRequest, payload: Payload) -> Task;
|
fn handle(&self, req: HttpRequest, payload: Payload) -> Task;
|
||||||
|
23
src/staticfiles.rs
Normal file
23
src/staticfiles.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![allow(dead_code, unused_variables)]
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use task::Task;
|
||||||
|
use route::RouteHandler;
|
||||||
|
use payload::Payload;
|
||||||
|
use httpcodes::HTTPOk;
|
||||||
|
use httprequest::HttpRequest;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct StaticFiles {
|
||||||
|
directory: String,
|
||||||
|
show_index: bool,
|
||||||
|
chunk_size: usize,
|
||||||
|
follow_synlinks: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static> RouteHandler<S> for StaticFiles {
|
||||||
|
|
||||||
|
fn handle(&self, req: HttpRequest, payload: Payload, state: Rc<S>) -> Task {
|
||||||
|
Task::reply(HTTPOk)
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,8 @@ use tokio_core::net::TcpStream;
|
|||||||
|
|
||||||
use date;
|
use date;
|
||||||
use route::Frame;
|
use route::Frame;
|
||||||
use httpmessage::{Body, HttpRequest, HttpResponse};
|
use httprequest::HttpRequest;
|
||||||
|
use httpmessage::{Body, HttpResponse};
|
||||||
|
|
||||||
type FrameStream = Stream<Item=Frame, Error=io::Error>;
|
type FrameStream = Stream<Item=Frame, Error=io::Error>;
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||||
|
@ -74,7 +74,8 @@ use context::HttpContext;
|
|||||||
use route::Route;
|
use route::Route;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed};
|
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed};
|
||||||
use httpmessage::{Body, ConnectionType, HttpRequest, HttpResponse};
|
use httprequest::HttpRequest;
|
||||||
|
use httpmessage::{Body, ConnectionType, HttpResponse};
|
||||||
|
|
||||||
use wsframe;
|
use wsframe;
|
||||||
use wsproto::*;
|
use wsproto::*;
|
||||||
|
@ -72,3 +72,25 @@ fn test_response_cookies() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
val[1],"name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400");
|
val[1],"name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_request_range_header() {
|
||||||
|
let req = HttpRequest::new(Method::GET, Uri::try_from("/").unwrap(),
|
||||||
|
Version::HTTP_11, HeaderMap::new());
|
||||||
|
let ranges = req.range(100).unwrap();
|
||||||
|
assert!(ranges.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_request_range_header() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(header::RANGE,
|
||||||
|
header::HeaderValue::from_static("bytes=0-4"));
|
||||||
|
|
||||||
|
let req = HttpRequest::new(Method::GET, Uri::try_from("/").unwrap(),
|
||||||
|
Version::HTTP_11, headers);
|
||||||
|
let ranges = req.range(100).unwrap();
|
||||||
|
assert_eq!(ranges.len(), 1);
|
||||||
|
assert_eq!(ranges[0].start, 0);
|
||||||
|
assert_eq!(ranges[0].length, 5);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user