mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-31 11:02:08 +01:00
Merge branch 'master' into replace-unsafe-content-length-helper
This commit is contained in:
commit
2a72e8d119
@ -3,13 +3,17 @@
|
|||||||
|
|
||||||
## [2.0.NEXT] - 2020-01-xx
|
## [2.0.NEXT] - 2020-01-xx
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Add helper function for creating routes with `TRACE` method guard `web::trace()`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Use `sha-1` crate instead of unmaintained `sha1` crate
|
* Use `sha-1` crate instead of unmaintained `sha1` crate
|
||||||
|
|
||||||
* Skip empty chunks when returning response from a `Stream` #1308
|
* Skip empty chunks when returning response from a `Stream` #1308
|
||||||
|
|
||||||
* Update the `time` dependency to 0.2.5
|
* Update the `time` dependency to 0.2.7
|
||||||
|
|
||||||
## [2.0.0] - 2019-12-25
|
## [2.0.0] - 2019-12-25
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ regex = "1.3"
|
|||||||
serde = { version = "1.0", features=["derive"] }
|
serde = { version = "1.0", features=["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_urlencoded = "0.6.1"
|
serde_urlencoded = "0.6.1"
|
||||||
time = { version = "0.2.5", default-features = false, features = ["std"] }
|
time = { version = "0.2.7", default-features = false, features = ["std"] }
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
open-ssl = { version="0.10", package = "openssl", optional = true }
|
open-ssl = { version="0.10", package = "openssl", optional = true }
|
||||||
rust-tls = { version = "0.16.0", package = "rustls", optional = true }
|
rust-tls = { version = "0.16.0", package = "rustls", optional = true }
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Update the `time` dependency to 0.2.5
|
* Update the `time` dependency to 0.2.7
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ serde_json = "1.0"
|
|||||||
sha-1 = "0.8"
|
sha-1 = "0.8"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
serde_urlencoded = "0.6.1"
|
serde_urlencoded = "0.6.1"
|
||||||
time = { version = "0.2.5", default-features = false, features = ["std"] }
|
time = { version = "0.2.7", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
# for secure cookie
|
# for secure cookie
|
||||||
ring = { version = "0.16.9", optional = true }
|
ring = { version = "0.16.9", optional = true }
|
||||||
|
@ -37,8 +37,12 @@ pub trait MessageBody {
|
|||||||
fn size(&self) -> BodySize;
|
fn size(&self) -> BodySize;
|
||||||
|
|
||||||
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>>;
|
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>>;
|
||||||
|
|
||||||
|
downcast_get_type_id!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downcast!(MessageBody);
|
||||||
|
|
||||||
impl MessageBody for () {
|
impl MessageBody for () {
|
||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
BodySize::Empty
|
BodySize::Empty
|
||||||
@ -416,7 +420,10 @@ where
|
|||||||
S: Stream<Item = Result<Bytes, Error>>,
|
S: Stream<Item = Result<Bytes, Error>>,
|
||||||
{
|
{
|
||||||
pub fn new(size: u64, stream: S) -> Self {
|
pub fn new(size: u64, stream: S) -> Self {
|
||||||
SizedStream { size, stream: Box::pin(stream) }
|
SizedStream {
|
||||||
|
size,
|
||||||
|
stream: Box::pin(stream),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,4 +650,18 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_body_casting() {
|
||||||
|
let mut body = String::from("hello cast");
|
||||||
|
let resp_body: &mut dyn MessageBody = &mut body;
|
||||||
|
let body = resp_body.downcast_ref::<String>().unwrap();
|
||||||
|
assert_eq!(body, "hello cast");
|
||||||
|
let body = &mut resp_body.downcast_mut::<String>().unwrap();
|
||||||
|
body.push_str("!");
|
||||||
|
let body = resp_body.downcast_ref::<String>().unwrap();
|
||||||
|
assert_eq!(body, "hello cast!");
|
||||||
|
let not_body = resp_body.downcast_ref::<()>();
|
||||||
|
assert!(not_body.is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ use h2::client::{handshake, Connection, SendRequest};
|
|||||||
use http::uri::Authority;
|
use http::uri::Authority;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
|
use pin_project::pin_project;
|
||||||
|
|
||||||
use super::connection::{ConnectionType, IoConnection};
|
use super::connection::{ConnectionType, IoConnection};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
@ -422,6 +423,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pin_project]
|
||||||
struct ConnectorPoolSupport<T, Io>
|
struct ConnectorPoolSupport<T, Io>
|
||||||
where
|
where
|
||||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||||
@ -439,7 +441,7 @@ where
|
|||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let this = unsafe { self.get_unchecked_mut() };
|
let this = self.project();
|
||||||
|
|
||||||
let mut inner = this.inner.as_ref().borrow_mut();
|
let mut inner = this.inner.as_ref().borrow_mut();
|
||||||
inner.waker.register(cx.waker());
|
inner.waker.register(cx.waker());
|
||||||
|
@ -990,7 +990,7 @@ impl<'a, 'b> PartialEq<Cookie<'b>> for Cookie<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Cookie, SameSite};
|
use super::{Cookie, SameSite};
|
||||||
use time::{offset, PrimitiveDateTime};
|
use time::PrimitiveDateTime;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format() {
|
fn format() {
|
||||||
@ -1015,7 +1015,7 @@ mod tests {
|
|||||||
assert_eq!(&cookie.to_string(), "foo=bar; Domain=www.rust-lang.org");
|
assert_eq!(&cookie.to_string(), "foo=bar; Domain=www.rust-lang.org");
|
||||||
|
|
||||||
let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
|
let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
|
||||||
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().using_offset(offset!(UTC));
|
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().assume_utc();
|
||||||
let cookie = Cookie::build("foo", "bar").expires(expires).finish();
|
let cookie = Cookie::build("foo", "bar").expires(expires).finish();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&cookie.to_string(),
|
&cookie.to_string(),
|
||||||
|
@ -6,7 +6,7 @@ use std::fmt;
|
|||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
use percent_encoding::percent_decode;
|
use percent_encoding::percent_decode;
|
||||||
use time::{Duration, offset};
|
use time::Duration;
|
||||||
|
|
||||||
use super::{Cookie, CookieStr, SameSite};
|
use super::{Cookie, CookieStr, SameSite};
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
|
|||||||
.or_else(|| time::parse(v, "%a, %d-%b-%Y %H:%M:%S").ok());
|
.or_else(|| time::parse(v, "%a, %d-%b-%Y %H:%M:%S").ok());
|
||||||
|
|
||||||
if let Some(time) = tm {
|
if let Some(time) = tm {
|
||||||
cookie.expires = Some(time.using_offset(offset!(UTC)))
|
cookie.expires = Some(time.assume_utc())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -216,7 +216,7 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Cookie, SameSite};
|
use super::{Cookie, SameSite};
|
||||||
use time::{offset, Duration, PrimitiveDateTime};
|
use time::{Duration, PrimitiveDateTime};
|
||||||
|
|
||||||
macro_rules! assert_eq_parse {
|
macro_rules! assert_eq_parse {
|
||||||
($string:expr, $expected:expr) => {
|
($string:expr, $expected:expr) => {
|
||||||
@ -376,7 +376,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
|
let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
|
||||||
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().using_offset(offset!(UTC));
|
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().assume_utc();
|
||||||
expected.set_expires(expires);
|
expected.set_expires(expires);
|
||||||
assert_eq_parse!(
|
assert_eq_parse!(
|
||||||
" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
|
" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
|
||||||
@ -385,7 +385,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
unexpected.set_domain("foo.com");
|
unexpected.set_domain("foo.com");
|
||||||
let bad_expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%S:%M").unwrap().using_offset(offset!(UTC));
|
let bad_expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%S:%M").unwrap().assume_utc();
|
||||||
expected.set_expires(bad_expires);
|
expected.set_expires(bad_expires);
|
||||||
assert_ne_parse!(
|
assert_ne_parse!(
|
||||||
" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
|
" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
//! Error and Result module
|
//! Error and Result module
|
||||||
use std::any::TypeId;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
@ -60,12 +59,6 @@ impl Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct with a private constructor, for use with
|
|
||||||
/// `__private_get_type_id__`. Its single field is private,
|
|
||||||
/// ensuring that it can only be constructed from this module
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct PrivateHelper(());
|
|
||||||
|
|
||||||
/// Error that can be converted to `Response`
|
/// Error that can be converted to `Response`
|
||||||
pub trait ResponseError: fmt::Debug + fmt::Display {
|
pub trait ResponseError: fmt::Debug + fmt::Display {
|
||||||
/// Response's status code
|
/// Response's status code
|
||||||
@ -89,43 +82,10 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
|
|||||||
resp.set_body(Body::from(buf))
|
resp.set_body(Body::from(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper method to get the type ID of the type
|
downcast_get_type_id!();
|
||||||
/// this trait is implemented on.
|
|
||||||
/// This method is unsafe to *implement*, since `downcast_ref` relies
|
|
||||||
/// on the returned `TypeId` to perform a cast.
|
|
||||||
///
|
|
||||||
/// Unfortunately, Rust has no notion of a trait method that is
|
|
||||||
/// unsafe to implement (marking it as `unsafe` makes it unsafe
|
|
||||||
/// to *call*). As a workaround, we require this method
|
|
||||||
/// to return a private type along with the `TypeId`. This
|
|
||||||
/// private type (`PrivateHelper`) has a private constructor,
|
|
||||||
/// making it impossible for safe code to construct outside of
|
|
||||||
/// this module. This ensures that safe code cannot violate
|
|
||||||
/// type-safety by implementing this method.
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn __private_get_type_id__(&self) -> (TypeId, PrivateHelper)
|
|
||||||
where
|
|
||||||
Self: 'static,
|
|
||||||
{
|
|
||||||
(TypeId::of::<Self>(), PrivateHelper(()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn ResponseError + 'static {
|
downcast!(ResponseError);
|
||||||
/// Downcasts a response error to a specific type.
|
|
||||||
pub fn downcast_ref<T: ResponseError + 'static>(&self) -> Option<&T> {
|
|
||||||
if self.__private_get_type_id__().0 == TypeId::of::<T>() {
|
|
||||||
// Safety: external crates cannot override the default
|
|
||||||
// implementation of `__private_get_type_id__`, since
|
|
||||||
// it requires returning a private type. We can therefore
|
|
||||||
// rely on the returned `TypeId`, which ensures that this
|
|
||||||
// case is correct.
|
|
||||||
unsafe { Some(&*(self as *const dyn ResponseError as *const T)) }
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -63,7 +63,7 @@ header! {
|
|||||||
(AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)+
|
(AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)+
|
||||||
|
|
||||||
test_accept_charset {
|
test_accept_charset {
|
||||||
/// Test case from RFC
|
// Test case from RFC
|
||||||
test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
|
test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ impl FromStr for HttpDate {
|
|||||||
|
|
||||||
fn from_str(s: &str) -> Result<HttpDate, ParseError> {
|
fn from_str(s: &str) -> Result<HttpDate, ParseError> {
|
||||||
match time_parser::parse_http_date(s) {
|
match time_parser::parse_http_date(s) {
|
||||||
Some(t) => Ok(HttpDate(t.using_offset(offset!(UTC)))),
|
Some(t) => Ok(HttpDate(t.assume_utc())),
|
||||||
None => Err(ParseError::Header)
|
None => Err(ParseError::Header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ impl From<OffsetDateTime> for HttpDate {
|
|||||||
|
|
||||||
impl From<SystemTime> for HttpDate {
|
impl From<SystemTime> for HttpDate {
|
||||||
fn from(sys: SystemTime) -> HttpDate {
|
fn from(sys: SystemTime) -> HttpDate {
|
||||||
HttpDate(PrimitiveDateTime::from(sys).using_offset(offset!(UTC)))
|
HttpDate(PrimitiveDateTime::from(sys).assume_utc())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,14 +66,14 @@ impl From<HttpDate> for SystemTime {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::HttpDate;
|
use super::HttpDate;
|
||||||
use time::{PrimitiveDateTime, date, time, offset};
|
use time::{PrimitiveDateTime, date, time};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date() {
|
fn test_date() {
|
||||||
let nov_07 = HttpDate(PrimitiveDateTime::new(
|
let nov_07 = HttpDate(PrimitiveDateTime::new(
|
||||||
date!(1994-11-07),
|
date!(1994-11-07),
|
||||||
time!(8:48:37)
|
time!(8:48:37)
|
||||||
).using_offset(offset!(UTC)));
|
).assume_utc());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"Sun, 07 Nov 1994 08:48:37 GMT".parse::<HttpDate>().unwrap(),
|
"Sun, 07 Nov 1994 08:48:37 GMT".parse::<HttpDate>().unwrap(),
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
pub mod body;
|
pub mod body;
|
||||||
mod builder;
|
mod builder;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
95
actix-http/src/macros.rs
Normal file
95
actix-http/src/macros.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! downcast_get_type_id {
|
||||||
|
() => {
|
||||||
|
/// A helper method to get the type ID of the type
|
||||||
|
/// this trait is implemented on.
|
||||||
|
/// This method is unsafe to *implement*, since `downcast_ref` relies
|
||||||
|
/// on the returned `TypeId` to perform a cast.
|
||||||
|
///
|
||||||
|
/// Unfortunately, Rust has no notion of a trait method that is
|
||||||
|
/// unsafe to implement (marking it as `unsafe` makes it unsafe
|
||||||
|
/// to *call*). As a workaround, we require this method
|
||||||
|
/// to return a private type along with the `TypeId`. This
|
||||||
|
/// private type (`PrivateHelper`) has a private constructor,
|
||||||
|
/// making it impossible for safe code to construct outside of
|
||||||
|
/// this module. This ensures that safe code cannot violate
|
||||||
|
/// type-safety by implementing this method.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn __private_get_type_id__(&self) -> (std::any::TypeId, PrivateHelper)
|
||||||
|
where
|
||||||
|
Self: 'static,
|
||||||
|
{
|
||||||
|
(std::any::TypeId::of::<Self>(), PrivateHelper(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate implementation for dyn $name
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! downcast {
|
||||||
|
($name:ident) => {
|
||||||
|
/// A struct with a private constructor, for use with
|
||||||
|
/// `__private_get_type_id__`. Its single field is private,
|
||||||
|
/// ensuring that it can only be constructed from this module
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct PrivateHelper(());
|
||||||
|
|
||||||
|
impl dyn $name + 'static {
|
||||||
|
/// Downcasts generic body to a specific type.
|
||||||
|
pub fn downcast_ref<T: $name + 'static>(&self) -> Option<&T> {
|
||||||
|
if self.__private_get_type_id__().0 == std::any::TypeId::of::<T>() {
|
||||||
|
// Safety: external crates cannot override the default
|
||||||
|
// implementation of `__private_get_type_id__`, since
|
||||||
|
// it requires returning a private type. We can therefore
|
||||||
|
// rely on the returned `TypeId`, which ensures that this
|
||||||
|
// case is correct.
|
||||||
|
unsafe { Some(&*(self as *const dyn $name as *const T)) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Downcasts a generic body to a mutable specific type.
|
||||||
|
pub fn downcast_mut<T: $name + 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
if self.__private_get_type_id__().0 == std::any::TypeId::of::<T>() {
|
||||||
|
// Safety: external crates cannot override the default
|
||||||
|
// implementation of `__private_get_type_id__`, since
|
||||||
|
// it requires returning a private type. We can therefore
|
||||||
|
// rely on the returned `TypeId`, which ensures that this
|
||||||
|
// case is correct.
|
||||||
|
unsafe {
|
||||||
|
Some(&mut *(self as *const dyn $name as *const T as *mut T))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
trait MB {
|
||||||
|
downcast_get_type_id!();
|
||||||
|
}
|
||||||
|
|
||||||
|
downcast!(MB);
|
||||||
|
|
||||||
|
impl MB for String {}
|
||||||
|
impl MB for () {}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_any_casting() {
|
||||||
|
let mut body = String::from("hello cast");
|
||||||
|
let resp_body: &mut dyn MB = &mut body;
|
||||||
|
let body = resp_body.downcast_ref::<String>().unwrap();
|
||||||
|
assert_eq!(body, "hello cast");
|
||||||
|
let body = &mut resp_body.downcast_mut::<String>().unwrap();
|
||||||
|
body.push_str("!");
|
||||||
|
let body = resp_body.downcast_ref::<String>().unwrap();
|
||||||
|
assert_eq!(body, "hello cast!");
|
||||||
|
let not_body = resp_body.downcast_ref::<()>();
|
||||||
|
assert!(not_body.is_none());
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use time::{PrimitiveDateTime, Date};
|
use time::{OffsetDateTime, PrimitiveDateTime, Date};
|
||||||
|
|
||||||
/// Attempt to parse a `time` string as one of either RFC 1123, RFC 850, or asctime.
|
/// Attempt to parse a `time` string as one of either RFC 1123, RFC 850, or asctime.
|
||||||
pub fn parse_http_date(time: &str) -> Option<PrimitiveDateTime> {
|
pub fn parse_http_date(time: &str) -> Option<PrimitiveDateTime> {
|
||||||
@ -19,7 +19,7 @@ fn try_parse_rfc_850(time: &str) -> Option<PrimitiveDateTime> {
|
|||||||
// If the `time` string contains a two-digit year, then as per RFC 2616 § 19.3,
|
// If the `time` string contains a two-digit year, then as per RFC 2616 § 19.3,
|
||||||
// we consider the year as part of this century if it's within the next 50 years,
|
// we consider the year as part of this century if it's within the next 50 years,
|
||||||
// otherwise we consider as part of the previous century.
|
// otherwise we consider as part of the previous century.
|
||||||
let now = PrimitiveDateTime::now();
|
let now = OffsetDateTime::now();
|
||||||
let century_start_year = (now.year() / 100) * 100;
|
let century_start_year = (now.year() / 100) * 100;
|
||||||
let mut expanded_year = century_start_year + dt.year();
|
let mut expanded_year = century_start_year + dt.year();
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## [0.2.NEXT] - 2020-xx-xx
|
## [0.2.1] - 2020-02-25
|
||||||
|
|
||||||
* Allow the handler function to be named as `config` #1290
|
* Add `#[allow(missing_docs)]` attribute to generated structs [#1368]
|
||||||
|
* Allow the handler function to be named as `config` [#1290]
|
||||||
|
|
||||||
|
[#1368]: https://github.com/actix/actix-web/issues/1368
|
||||||
|
[#1290]: https://github.com/actix/actix-web/issues/1290
|
||||||
|
|
||||||
## [0.2.0] - 2019-12-13
|
## [0.2.0] - 2019-12-13
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-web-codegen"
|
name = "actix-web-codegen"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
description = "Actix web proc macros"
|
description = "Actix web proc macros"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
@ -17,6 +17,6 @@ syn = { version = "^1", features = ["full", "parsing"] }
|
|||||||
proc-macro2 = "^1"
|
proc-macro2 = "^1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = { version = "1.0.0" }
|
actix-rt = "1.0.0"
|
||||||
actix-web = { version = "2.0.0-rc" }
|
actix-web = "2.0.0"
|
||||||
futures = { version = "0.3.1" }
|
futures = "0.3.1"
|
||||||
|
@ -191,7 +191,7 @@ impl Route {
|
|||||||
let extra_guards = &self.args.guards;
|
let extra_guards = &self.args.guards;
|
||||||
let resource_type = &self.resource_type;
|
let resource_type = &self.resource_type;
|
||||||
let stream = quote! {
|
let stream = quote! {
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types, missing_docs)]
|
||||||
pub struct #name;
|
pub struct #name;
|
||||||
|
|
||||||
impl actix_web::dev::HttpServiceFactory for #name {
|
impl actix_web::dev::HttpServiceFactory for #name {
|
||||||
|
@ -7,6 +7,12 @@
|
|||||||
//! Actix web is a small, pragmatic, and extremely fast web framework
|
//! Actix web is a small, pragmatic, and extremely fast web framework
|
||||||
//! for Rust.
|
//! for Rust.
|
||||||
//!
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! The `#[actix_rt::main]` macro in the example below is provided by the Actix runtime
|
||||||
|
//! crate, [`actix-rt`](https://crates.io/crates/actix-rt). You will need to include
|
||||||
|
//! `actix-rt` in your dependencies for it to run.
|
||||||
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use actix_web::{web, App, Responder, HttpServer};
|
//! use actix_web::{web, App, Responder, HttpServer};
|
||||||
//!
|
//!
|
||||||
|
18
src/web.rs
18
src/web.rs
@ -193,6 +193,24 @@ pub fn head() -> Route {
|
|||||||
method(Method::HEAD)
|
method(Method::HEAD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create *route* with `TRACE` method guard.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use actix_web::{web, App, HttpResponse};
|
||||||
|
///
|
||||||
|
/// let app = App::new().service(
|
||||||
|
/// web::resource("/{project_id}")
|
||||||
|
/// .route(web::trace().to(|| HttpResponse::Ok()))
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In the above example, one `HEAD` route gets added:
|
||||||
|
/// * /{project_id}
|
||||||
|
///
|
||||||
|
pub fn trace() -> Route {
|
||||||
|
method(Method::TRACE)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create *route* and add method guard.
|
/// Create *route* and add method guard.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## [Unreleased] - 2020-xx-xx
|
## [Unreleased] - 2020-xx-xx
|
||||||
|
|
||||||
* Update the `time` dependency to 0.2.5
|
* Update the `time` dependency to 0.2.7
|
||||||
|
|
||||||
|
|
||||||
## [1.0.0] - 2019-12-13
|
## [1.0.0] - 2019-12-13
|
||||||
|
@ -51,7 +51,7 @@ serde_json = "1.0"
|
|||||||
sha1 = "0.6"
|
sha1 = "0.6"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
serde_urlencoded = "0.6.1"
|
serde_urlencoded = "0.6.1"
|
||||||
time = { version = "0.2.5", default-features = false, features = ["std"] }
|
time = { version = "0.2.7", default-features = false, features = ["std"] }
|
||||||
open-ssl = { version="0.10", package="openssl", optional = true }
|
open-ssl = { version="0.10", package="openssl", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user